一、自动内存管理:
JVM运行时数据区图
1、程序计数器:
占用较小的空间,可以看作当前线程所执行字节码的行号指示器。分支,循环,跳转和异常处理都通过程序计数器来完成。
线程切换时恢复到字节码执行位置也依赖程序计数器,每个线程都有自己的程序计数器。
2、Java虚拟机栈
Java虚拟机栈是线程私有的,描述的是Java方法执行的内存模型。每个方法在执行时都会创建栈帧,用于存储操作数栈,局部变量表,动态链接和方法出口等信息;每个方法的从调用到执行完成,对应着一个栈帧的入栈到出栈的过程。
局部变量表存储基本的数据类型和引用类型,一般在编译时确认大小,在方法执行中不会改变局部变量表的大小;
3、本地方法栈
为虚拟机用到的本地方法服务。
4、Java堆
在虚拟机启动时创建,存放对象的实例,是线程共享区域。根据分代垃圾收集算法,还分为新生代和老年代。
5、方法区
用于存储虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等。对HotSpot虚拟机来讲,也称为永久代(PerGen)。
运行时常量池属于方法区的一部分,Class文件除了描述类版本,字段,方法等外,还有常量池部分,用于存储编译时期生成的字面量或版本号引用。
常量池可以在代码运行时加入,比如String类intern()方法。
6、直接内存
直接内存(Direct Memory)不是运行时数据区的一部分,也不是JVM规范的中的定义内存。
在NIO中的基于通道和缓冲区的IO方式,它直接使用Native函数分配堆外内存,然后通过存储在Java堆中的DirectBuffer对象作为这块内存的引用进行操作。
二、对象创建访问
1、对象的创建(Hotspot虚拟机)
对象创建过程:
new指令->常量池中定位类的符号引用->类是否加载、解析、初始化->为对象在堆上分配内存->执行
对象的内存布局:
对象头(Header):运行时数据(Hashcode、GC分代年龄、锁状态标识、线程持有的锁、偏向线程ID、偏向时间戳)
32/64位
实例数据(instance data):
程序定义的各类型的数据内容。
对齐填充(Padding):
对象的大小必须是8位的整数倍,不足则补齐;
2、对象的访问:
方法一、垃圾回收时只改变句柄中的实例数据指针
方法二、速度快,Hotspot虚拟机使用。
三、OutOfMemoryError:
1、堆溢出:
运行下列代码:
1 | * |
输出了以下错误:
1 | java.lang.OutOfMemoryError: Java heap space |
使用Eclipse Memory Analyzer工具分析dump文件
MAT的地址为:http://www.eclipse.org/mat/downloads.php
eclipse插件升级地址为:http://download.eclipse.org/mat/1.5/update-site/
2 、虚拟机栈溢出
1 | /** |
运行后:
1 | stack length=21824 |
3、方法区和运行时常量池溢出
1)、常量池溢出
代码:
/** * VM Args:-XX:PermSize=10M -XX:MaxPermSize=10m * @author weining * */ public class RuntimeConstantPoolOOM { public static void main(String[] args) { List<String> list = new ArrayList<String>(); int i = 0; while(true){ list.add(String.valueOf(i++).intern()); } } }
2)、方法区溢出 加载过多的类信息,常见spring框架,JSP编译等。1
2
3
4
5
6
7
运行后:
```java
Exception in thread "main" java.lang.OutOfMemoryError: PermGen space
at java.lang.String.intern(Native Method)
at oom.RuntimeConstantPoolOOM.main(RuntimeConstantPoolOOM.java:18)运行时出现:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30/**
* VM Args:-XX:PermSize=10M -XX:MaxPermSize=10m
* @author weining
*
*/
public class JavaMethodAreaOOM {
public static void main(String[] args) {
while(true){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(OOMObject.class);
enhancer.setUseCache(false);
enhancer.setCallback(new MethodInterceptor(){
public Object intercept(Object obj, Method method,
Object[] args, MethodProxy proxy) throws Throwable {
return proxy.invokeSuper(obj, args);
}
});
enhancer.create();
}
}
static class OOMObject{
}
}4、直接内存溢出 通过-XX:MaxDirectMemorySize指定,否则=-Xmx NIO代码中出现,dump文件较小。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17Exception in thread "main" net.sf.cglib.core.CodeGenerationException: java.lang.reflect.InvocationTargetException-->null
at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:237)
at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:377)
at net.sf.cglib.proxy.Enhancer.create(Enhancer.java:285)
at oom.JavaMethodAreaOOM.main(JavaMethodAreaOOM.java:31)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at net.sf.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:384)
at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:219)
... 3 more
Caused by: java.lang.OutOfMemoryError: PermGen space
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631)
at java.lang.ClassLoader.defineClass(ClassLoader.java:615)
... 8 more运行后:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19/**
*VM Args:-Xmx20m -XX:MaxDirectMemorySize=10m
* @author weining
*
*/
public class DirectMemoryOOM {
private static final int _1MB = 1024*1024;
public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException {
Field unsafeField = Unsafe.class.getDeclaredFields()[0];
unsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe)unsafeField.get(null);
while(true){
unsafe.allocateMemory(_1MB);
}
}
}1
2
3Exception in thread "main" java.lang.OutOfMemoryError
at sun.misc.Unsafe.allocateMemory(Native Method)
at oom.DirectMemoryOOM.main(DirectMemoryOOM.java:21)