【发布时间】:2011-09-29 08:34:39
【问题描述】:
我在分配和释放字节数组时遇到 OutOfMemoryError java heap 异常,即使有足够的空闲内存用于分配。 下面有一个简短的日志。我从在不同的 JVM 上运行时知道,问题是由于内存碎片造成的,最大的空闲块只有大约 6MB。我认为 java (oracle) JVM 应该处理碎片化的内存。
这是我的测试:
- 使用参数 -Xms10M -Xmx10M 设置 java JVM
- 我分配了一个占 JVM 内存 90% 的字节数组。
- 然后将此字节数组设置为空,然后尝试重新分配占 JVM 内存 90% 的字节数组。
- 我们从日志中看到 JVM 内存已重置为全量,但我们无法分配相同数量的内存。
- 因此内存必须是碎片化的?
这是我的详细信息:
Total Free Memory: 9881728
Attempting to Allocate Array of size: 6917209
Freeing Allocated Array of size: 6917209
Total Free Memory: 9881728
Attempting to Allocate Array of size: 6917209
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
我正在运行的另一个 JVM 是 Skelmir 的 CEE-J,我在低内存设备上运行,因此无法设置 MaxPermSize。有趣的是,java堆被分成不同的区域,这些区域在垃圾收集后可以改变大小吗?我已经运行了另一个测试, 首先为大约 95% 的内存创建一个字节数组, 然后再次释放阵列, 然后我创建了一组包含哈希图的对象数组,每个对象都有一个条目, 我清除数组和映射,然后再次重新分配相同的数组。
我每次分配和释放时都会检查内存。这样说10次后, 我最后一次释放内存, 然后我检查内存,看到我有完整的 JVM 分配, 然后我尝试再次分配 95% 的 JVM 分配并获得相同的 JVM 内存不足异常,即使它说我有足够的内存可以分配?
public static void main(String[] args) throws InterruptedException {
Runtime s_runtime = Runtime.getRuntime ();
long used_memory = s_runtime.totalMemory () - s_runtime.freeMemory ();
long start_memory = used_memory;
long freeMemory = s_runtime.freeMemory();
Integer numSubMemories = 1;
Integer numMapEntries = 1;
Integer numIterations = 1;
float percentMem = (float) 1.0;
if(args.length>0){
if(args[0]!=null){
String subEntries = args[0];
if(subEntries.length()>0){
numSubMemories = Integer.parseInt(subEntries);
}
}
if(args[1]!=null){
String mapEntries = args[1];
if(mapEntries.length()>0){
numMapEntries = Integer.parseInt(mapEntries);
}
}
if(args[2]!=null){
String numIts = args[2];
if(numIts.length()>0){
numIterations = Integer.parseInt(numIts);
}
}
if(args[3]!=null){
String percentMemArg = args[3];
if(percentMemArg.length()>0){
percentMem = Float.parseFloat(percentMemArg);
}
}
}
System.out.println("Total Free Memory: " + freeMemory);
int numBytes = (int) (freeMemory * percentMem);
System.out.println("Attempting to Allocate Array of size: " + numBytes);
byte[] mbyteArray = new byte[numBytes];
System.out.println("Freeing Allocated Array of size: " + numBytes);
mbyteArray = null;
TestMemory myMemory = new TestMemory(numSubMemories,numMapEntries);
used_memory = s_runtime.totalMemory () - s_runtime.freeMemory ();
System.out.println("Used Memory: " + used_memory);
long after_allocation_memory = used_memory;
for(int i=0;i<numIterations;i++){
System.out.println("\t\t--Iteration: "+ i + " about to release Memory");
myMemory.releaseMemoryArray(numSubMemories);
System.out.println("\t\t--Iteration: "+ i + " about to reallocate Memory");
myMemory.reAllocateMemoryArray(numSubMemories,numMapEntries);
used_memory = s_runtime.totalMemory () - s_runtime.freeMemory ();
System.out.println("\t\t--Used Memory: " + used_memory);
System.out.println("\t\t--Max Memory: " + s_runtime.maxMemory());
System.out.println("\t\t--Free Memory: " + s_runtime.freeMemory());
System.gc();
System.out.flush();
}
System.out.println("Releasing the Arrays for the last time");
myMemory.releaseMemoryArray(numSubMemories);
System.gc();
freeMemory = s_runtime.freeMemory();
//numBytes = (int)(freeMemory*0.95);
System.out.println("Attempting to Allocate Array of size: " + numBytes);
System.out.println("Total Free Memory: " + freeMemory);
mbyteArray = new byte[numBytes];
long end_memory = used_memory;
//System.gc();
Thread.sleep(6000);
used_memory = s_runtime.totalMemory () - s_runtime.freeMemory ();
System.out.println("------Results---------");
System.out.println(" Start Memory: " + start_memory);
System.out.println(" After Memory: " + after_allocation_memory);
System.out.println(" End Memory: " + end_memory);
System.out.println("End Release Memory: " + used_memory);
}
第二次测试的输出日志。 总可用内存:9881728 尝试分配大小数组:6917209 释放大小的分配数组:6917209 已用内存:7519744 -Iteration: 0 即将释放内存 -Iteration: 0 即将重新分配内存 -已用内存:7890928 -最大内存:10092544 - 空闲内存:2147808 -Iteration: 1 即将释放内存 -Iteration: 1 即将重新分配内存 -已用内存:930952 -最大内存:10092544 - 空闲内存:9107792 -Iteration: 2 即将释放内存 -Iteration: 2 即将重新分配内存 -已用内存:1181832 -最大内存:10092544 - 空闲内存:8856912 -Iteration: 3 即将释放内存 -Iteration: 3 即将重新分配内存 -已用内存:1190552 -最大内存:10092544 - 空闲内存:8848192 -Iteration: 4 即将释放内存 -Iteration: 4 即将重新分配内存 -已用内存:902408 -最大内存:10092544 - 空闲内存:9190136 -Iteration: 5 即将释放内存 -Iteration: 5 即将重新分配内存 -已用内存:902408 -最大内存:10092544 - 空闲内存:9190136 -Iteration: 6 即将释放内存 -Iteration: 6 即将重新分配内存 -已用内存:902408 -最大内存:10092544 - 空闲内存:9190136 -Iteration: 7 即将释放内存 -Iteration: 7 即将重新分配内存 -已用内存:902408 -最大内存:10092544 - 空闲内存:9190136 -Iteration: 8 即将释放内存 -Iteration: 8 即将重新分配内存 -已用内存:902408 -最大内存:10092544 - 空闲内存:9190136 -Iteration: 9 即将释放内存 -Iteration: 9 即将重新分配内存 -已用内存:902408 -最大内存:10092544 - 空闲内存:9190136 最后一次释放阵列 尝试分配大小数组:6917209 总可用内存:9956688 线程“主”java.lang.OutOfMemoryError 中的异常:Java 堆空间
【问题讨论】:
-
你能展示一下Java代码吗?
-
另一个注意事项,我使用的 CEE-J JVM 使用 Mark and Sweep 垃圾收集,这是否意味着 Java 堆没有被拆分为多个区域(代)或者拆分不同垃圾回收的类型?