一、内存分配与
1、OutOfMemoryError (堆异常)
Eclipse:
VM argument:
(1)-verbose:gc:显示虚拟机内存回收信息。
[GC (Allocation Failure) 952K->767K(59392K), 0.0073992 secs]
有952-767=185k的内存被回收。java堆大小为59392k。
(2)
-Xms20M //堆最小值为20MB
-Xmx20M //堆最大值20MB
-Xmn20M //存储新生成对象的空间
-XX:SurvivorRatio=4 //年轻代中Eden区与Survivor区的大小比值
/*VM arguments:
-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8
*/
package com.hi;
import java.util.*;
public class myjava {
public static void main(String[] args) {
// TODO Auto-generated method stub
List list=new ArrayList();
while(true){
list.add(new myjava());
}
}
} //抛出堆内存异常(java.lang.OutOfMemoryError: Java heap space)
2、虚拟机栈和方法栈异常
若线程请求的栈深度大于jvm允许的最大深度,抛出StackOverflowError
若jvm在扩展栈时,无法申请足够内存,抛出OutOfMemoryError
//vm arguments : -Xss128k (栈大小)
import java.util.*;
public class myjava {
private int size=1;
public void stackleak(){
size++;
stackleak();
}
public static void main(String[] args) {
// TODO Auto-generated method stub
myjava com=new myjava();
com.stackleak();
}
} //java.lang.StackOverflowError
操作系统为每个进程分配的最大内存为2GB,对于jvm进程,若分配给栈的容量越大,可建立的新的线程就越少。建立新的线程容易把内存耗尽。
例如:
while (true){
Thread trd=new Thread(new Runnable(){public void run(){fun();}});
} //OutOfMemoryError
3、运行时常量池溢出:
package com.hi;
import java.util.*;
public class myjava {
public static void main(String[] args) {
List list=new ArrayList();
int i=0;
while(true){
list.add(String.valueOf(i++).intern());
} //intern() :若常量池没有当前的这个对象,则将此对相关加入常量池。
}
} //OutOfMemoryError (RuntimeConstantPoolOOM)
4、方法区溢出:
方法区:类信息(类名、修饰符、常量池、方法描述等)
使用cglib不断扩充类 ,使方法区内存溢出。//OutOfMemory
5、直接内存溢出:
VM arguments:
-Xmx20M -XX:MaxDirectMemorySize=10M
package com.hi;
import java.lang.reflect.Field;
import sun.misc.Unsafe; //Unsafe 类用于分配内存
public class myjava {
private static final int i=1024*1024;
public static void main(String[] args) throws Exception{
Field unsafeField=Unsafe.class.getDeclaredFields()[0];
unsafeField.setAccessible(true);
Unsafe us=(Unsafe)unsafeField.get(null);
while(true){
us.allocateMemory(i);
}
}
}
运行结果:
Exception in thread “main” java.lang.OutOfMemoryError
at sun.misc.Unsafe.allocateMemory(Native Method)
at com.hi.myjava.main(myjava.java:15)
6、内存分配与回收:
Minor GC:新生代回收
Major GC/ Full GC :老年代回收
对象(小对象)优先在Eden分配。大对象直接分配到老年代。???
package com.hi;
public class myjava {
public static final int _1MB=1024*1024;
public static void main(String[] args){
byte[] a1,a2,a3,a4;
a1=new byte[2*_1MB];
a2=new byte[2*_1MB];
a3=new byte[2*_1MB];
a4=new byte[3*_1MB]; //3MB被分配在Eden,但是4MB就被直接分配到OldGen??(并不是Eden区满了,才垃圾回收)
}
}
vm:-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:SurvivorRatio=8 -XX:+PrintGCDetails
输出:
[GC (Allocation Failure) [PSYoungGen: 7652K->840K(9216K)] 7652K->6992K(19456K), 0.0042060 secs] [Times: user=0.05 sys=0.02, real=0.00 secs]
[Full GC (Ergonomics) [PSYoungGen: 840K->0K(9216K)] [ParOldGen: 6152K->6862K(10240K)] 6992K->6862K(19456K), [Metaspace: 2751K->2751K(1056768K)], 0.0085179 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
Heap
PSYoungGen total 9216K, used 3318K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
eden space 8192K, 40% used [0x00000000ff600000,0x00000000ff93d8f0,0x00000000ffe00000)
from space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000)
to space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
ParOldGen total 10240K, used 6862K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
object space 10240K, 67% used [0x00000000fec00000,0x00000000ff2b3a08,0x00000000ff600000)
Metaspace used 2760K, capacity 4486K, committed 4864K, reserved 1056768K
class space used 305K, capacity 386K, committed 512K, reserved 1048576K
package com.hi;
public class myjava {
public static final int _1MB=1024*1024;
public static void main(String[] args){
byte[] a1,a2,a3,a4;
a1=new byte[2*_1MB];
a2=new byte[2*_1MB];
a3=new byte[2*_1MB];
a4=new byte[8*_1MB]; //大对象直接分配到oldgen
}
}
//vm:-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:SurvivorRatio=8 -XX:+PrintGCDetails
//输出信息:
Heap
PSYoungGen total 9216K, used 7816K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
eden space 8192K, 95% used [0x00000000ff600000,0x00000000ffda22e8,0x00000000ffe00000)
from space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
to space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000)
ParOldGen total 10240K, used 8192K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
object space 10240K, 80% used [0x00000000fec00000,0x00000000ff400010,0x00000000ff600000)
Metaspace used 2757K, capacity 4486K, committed 4864K, reserved 1056768K
class space used 305K, capacity 386K, committed 512K, reserved 1048576K
长期存活的对象进入老年代:
每个对象设置一个年龄计数器。经历一次Minor GC并且能被Survivor,年龄加1。若年龄大于15(默认),会被移动到老年代。
-XX:MaxTenuringThreshold=1 ,设置移动时的年龄
动态对象年龄的判定:若Survivor空间中相同年龄的对象的大小之和大于Survivor空间的一般,则大于或等于该年龄的对象就可以进入老年代。无需判定年龄计数器。
空间分配担保:
vm会判断即将晋升到老年代的对象的平均大小,若大于老年代剩余空间,直接Full GC。若小于,要查看HandlePromotionFailure是否允许担保失败,若允许,只会Minor GC,若不允许,直接Full GC。
-XX:+PrintCompilation:输出编译信息
package com.hi;
public class myjava {
public static final int NUM=15000;
public static int doubleValue(int i){
return i*2;
}
public static long calSum(){
long sum=0;
for(int i=0;i<100;i++){
sum+=doubleValue(i);
}
return sum;
}
public static void main(String[] args) throws Exception{
for(int i=0;i
运行输出信息:
180 1 3 java.lang.String::equals (81 bytes) 197 5 n 0 java.lang.System::arraycopy (native) (static) 197 4 4 java.lang.String::length (6 bytes) 198 2 3 java.lang.String::hashCode (55 bytes) 198 3 4 java.lang.String::charAt (29 bytes) 199 6 3 java.util.Arrays::copyOfRange (63 bytes) 200 8 3 java.lang.AbstractStringBuilder::ensureCapacityInternal (16 bytes) 200 9 3 java.lang.Object::
(1 bytes) 200 7 3 java.lang.String:: (62 bytes) 201 10 3 java.lang.CharacterData::of (120 bytes) 201 11 3 java.lang.CharacterDataLatin1::getProperties (11 bytes) 202 13 3 java.lang.Character::toLowerCase (9 bytes) 202 14 3 java.lang.CharacterDataLatin1::toLowerCase (39 bytes) 202 12 3 java.lang.AbstractStringBuilder::append (29 bytes) 203 15 3 java.lang.StringBuilder::append (8 bytes) 203 16 3 java.io.WinNTFileSystem::isSlash (18 bytes) 204 17 s 3 java.lang.StringBuffer::append (13 bytes) 208 18 3 java.lang.String::getChars (62 bytes) 212 19 3 java.io.BufferedInputStream::getBufIfOpen (21 bytes) 212 20 s 3 java.io.BufferedInputStream::read (49 bytes) 213 21 3 java.io.DataInputStream::readUTF (501 bytes) 216 24 3 java.io.DataInputStream::readFully (63 bytes) 216 25 s 3 java.io.BufferedInputStream::read (113 bytes) 217 27 3 java.io.DataInputStream::readShort (40 bytes) 217 26 3 java.io.BufferedInputStream::read1 (108 bytes) 218 22 3 java.io.DataInputStream::readUTF (5 bytes) 218 23 3 java.io.DataInputStream::readUnsignedShort (39 bytes) 219 28 3 java.util.HashMap::hash (20 bytes) 223 29 3 java.lang.String::indexOf (70 bytes) 229 30 3 java.lang.Math::max (11 bytes) 231 31 3 java.lang.AbstractStringBuilder::append (50 bytes) 232 32 3 java.lang.StringBuilder::append (8 bytes) 261 33 1 java.lang.Object:: (1 bytes) 262 9 3 java.lang.Object:: (1 bytes) made not entrant 262 34 3 java.lang.Math::min (11 bytes) 264 35 3 com.hi.myjava::doubleValue (4 bytes) 264 36 1 com.hi.myjava::doubleValue (4 bytes) 264 35 3 com.hi.myjava::doubleValue (4 bytes) made not entrant 264 37 3 com.hi.myjava::calSum (26 bytes) 265 38 % 4 com.hi.myjava::calSum @ 7 (26 bytes) 267 39 4 com.hi.myjava::calSum (26 bytes) 269 37 3 com.hi.myjava::calSum (26 bytes) made not entrant