以下是检查内存的代码片段
public class TestFreeMemory {
public static void main(String ... args){
Runtime rt = Runtime.getRuntime();
System.out.println("Free Memory (Before GC): " + rt.freeMemory());
rt.gc();
System.out.println("Free Memory (After GC1): " + rt.freeMemory());
rt.gc(); // Second time to ensure results are consistent
// MAY BE has collected all non-reachable objects
System.out.println("Free Memory (After GC2): " + rt.freeMemory());
String s = new String("abcd");
Integer i = new Integer(12345);
System.out.println("Free Memory (After String Creation): " + rt.freeMemory());
// Why is freeMemory not reflecting the memory consumed by two objects
}
}
,输出
Free Memory (Before GC): 1859672
Free Memory (After GC1): 1911768
Free Memory (After GC2): 1911768
Free Memory (After String Creation): 1911768
为什么freeMemory没有反映两个对象消耗的内存?
更清楚的是,问题是getMemory()调用没有显示预期结果,即使创建了两个对象并且与GC无关。两个GC调用只是为了确保getMemory()调用的数量是正确的..而且BTW,在创建对象后没有GC调用..所以请注意我在创建对象后没有尝试GC ..
答案 0 :(得分:3)
HotSpot JVM上的内存管理:
另一个理想的垃圾收集器 特征是的限制 碎片。 当记忆为 垃圾对象被释放,免费 空间可能出现在小块中 各种可能的领域 没有足够的空间在任何一个 用于的连续区域 分配一个大对象。一个 消除碎片的方法 被称为压实,在其中讨论 各种垃圾收集器设计 选择如下。
Memory Management in HotSpot JVM (PDF Format).
此行为可能非常依赖于垃圾回收的特定实现。例如:
Parallel Mark Compact
- 停止的环球
- 堆分为固定大小的块(现在大约2kb,可能会增加或者是 受人体工程学影响)
- Chunk是实时数据汇总的单位
- 平行标记
- 在外部位图中记录实时数据地址
- 查找每个块实时数据大小
- 找到密集的块,即(几乎)充满活动对象的块
我已经制作了这个示例(使用滥用字符串连接来消耗更多内存):
public class TestFreeMemory {
static void allocateSomeMemory(){
long[][] array = new long[400][400];
}
public static void main(String ... args){
Runtime rt = Runtime.getRuntime();
allocateSomeMemory(); // once we leave, our array is not reachable anymore
System.out.println("Free Memory (Before GC): " + rt.freeMemory());
rt.gc();
System.out.println("Free Memory (After GC): " + rt.freeMemory());
String a = new String("A");
for(int i = 0; i < 100; i++){
a+="B";
}
System.out.println("Free Memory (After String Creation): " + rt.freeMemory());
// Less free memory expected.
}
}
<强>输出强>:
可用内存(GC之前):3751800
可用内存(GC后):5036104
可用内存(字符串创建后): 5012048
如果我在循环中使用相对较少的迭代次数(例如10),额外空间不会出现在freeMemory()
中,我会得到类似的结果:
可用内存(GC之前):3751800
可用内存(GC后):5036040
可用内存(字符串创建后): 5036040
答案 1 :(得分:1)
这是一个很好的问题,因为您希望反映内存使用量的增加,这似乎是一个逻辑测试。您可以假设这种行为是因为堆管理和垃圾收集系统比简单的Free vs Allocated边界稍微复杂一些。分配可能是在比你的一个String +一个整数大得多的块中完成的,所以可以通过总结空闲块来计算空闲内存。
答案 2 :(得分:0)
调用GC时,GC不释放内存,但需要更多内存时。
答案 3 :(得分:0)
尝试分配更多内存,您会看到增加。我想java预分配至少足够的字节(多么聪明!)来保存你的字符串或者它们已经在字符串池中了。