Osheep

时光不回头,当下最重要。

Java内存中对象大小计算

在Java开发中,我们常常需要预估获取查看虚拟机内存的使用情况,因为内存的使用率会导致程序的异常发生。 
接下来,我们使用到一个抽象的工具类,工具类调用Java中内存方法来进行使用。

SizeOf类:

/**
 * @ClassName: SizeOf
 * @Description: Java内存中对象大小计算
 * @author hpboys
 * @date 2015-9-3 下午4:40:15
 * @version V1.0.1
 */
public abstract class SizeOf {

	private final Runtime s_runtime = Runtime.getRuntime();
	
	private Float totalSize;//总内存大小
	private int count;//对象总数
	
	public int getCount() {
		return count;
	}

	public void setCount(int count) {
		this.count = count;
	}

	/**
	 * 得到总计算对象的总数
	 * @return 被测试类的实例总数
	 */
	public Float getTotalSize() {
		return totalSize;
	}

	public void setTotalSize(Float totalSize) {
		this.totalSize = totalSize;
	}

	/**
	 * 子类负责覆盖该方法以提供被测试类的实例
	 * @return 被测试类的实例
	 */
	protected abstract Object newInstance();

	/**
	 * 计算实例的大小(字节数)
	 * @return 实例所占内存的字节数
	 * @throws Exception
	 */
	public int size() throws Exception {

		// 垃圾回收
		runGC();

		// 提供尽可能多(00万)的实例以使计算结果更精确
		final int count = this.count;
		Object[] objects = new Object[count];

		// 实例化前堆已使用大小
		long heap1 = usedMemory();
		// 多实例化一个对象
		for (int i = -1; i < count; ++i) {
			Object object = null;

			// 实例化对象
			object = newInstance();

			if (i >= 0) {
				objects[i] = object;
			} else {
				// 释放第一个对象
				object = null;
				// 垃圾收集
				runGC();
				// 实例化之前堆已使用大小
				heap1 = usedMemory();
			}
		}

		runGC();
		// 实例化之后堆已使用大小
		long heap2 = usedMemory();
		final int size = Math.round(((float) (heap2 - heap1)) / count);
		setTotalSize((float) (heap2 - heap1));
		// 释放内存
		for (int i = 0; i < count; ++i) {
			objects[i] = null;
		}
		objects = null;
		return size;
	}

	private void runGC() throws Exception {
		// 执行多次以使内存收集更有效
		for (int r = 0; r < 4; ++r) {
			_runGC();
		}
	}

	private void _runGC() throws Exception {
		long usedMem1 = usedMemory();
		long usedMem2 = Long.MAX_VALUE;
		for (int i = 0; (usedMem1 < usedMem2) && (i < 500); ++i) {
			s_runtime.runFinalization();
			s_runtime.gc();
			Thread.currentThread().yield();
			usedMem2 = usedMem1;
			usedMem1 = usedMemory();
		}
	}

	/**
	 * 堆中已使用内存
	 * @return 堆中已使用内存
	 */
	private long usedMemory() {
		return s_runtime.totalMemory() - s_runtime.freeMemory();
	}
}

运用内存计算类

import java.util.Date;

import com.hna.billbao.pojo.GzbProfitRecord;
import com.hna.billbao.test.pojo.SizeOf;

public class TestMemory extends SizeOf{
	
	public static void main(String[] args) throws Exception {
		SizeOf sizeOf = new TestMemory();
		sizeOf.setCount(1046356);
		System.out.println("统计总对象数量:" + sizeOf.getCount() + " 个");
		System.out.println("单个对象所占内存:" + sizeOf.size() + " 字节");
		System.out.println("总共所占内存:" + sizeOf.getTotalSize()/1024/1024 + " Mb");
	}

	@Override
	protected Object newInstance() {
		GzbProfitRecord tranRecord = new GzbProfitRecord();
		tranRecord.setAcctId(Long.valueOf(100000));
		tranRecord.setBillRate("0.55");
		tranRecord.setCreateDate(new Date());
		tranRecord.setProfitAmount("100000");
		tranRecord.setTotalAmount("200");
		return tranRecord;
	}
}

测试结果

统计总对象数量:106356 个
单个对象所占内存:72 字节
总共所占内存:7.3031006 Mb

这样,我们就能准确的计算出,Java对象在内存中大小如何了。

点赞