JVM运行时内存结构
先上图
JVM内存结构
1.程序计数器
较小的一块内存,可以看作当前线程执行的字节码的行号指示器,字节码解释器通过这个计数器的值选择下一条需要执行的字节码指令,分支,循环,异常处理,线程恢复都依赖此。属于线程私有。
2.虚拟机栈
属于线程私有,与线程生命周期相同,每个方法执行同时会创建一个栈帧,存储局部变量表,操作数栈,动态链接,方法出口等信息。每个方法调用对应一个栈帧的入栈和出栈。
3.本地方法栈
和虚拟机栈类似,不同之处在于本地方法栈为使用到的Native方法本地调用服务。对本地方法没有强制规定,语言,方式,数据结构。有的虚拟机将它和虚拟机栈合二为一,可能抛出StackOverflowError和OutOfMemoryError。
4.堆
是被所有线程共享的一块内存,用于分配对象实例,可以细分为新生代,老年代,Eden区,Fro mSurvivor 和 ToSurvivor等。可以通过JVM启动参数配置初始大小,即-Xmx -Xms -Xmn等参数设置。
JVM堆内存
5.方法区
用于存储已经被虚拟机加载的类信息,常量,静态变量,编译后的代码等。一般来说,在常用的HotSpot上,可以把方法区叫做永久代,Permanent Generation
5.1 运行时常量池
属于方法区的一部分,在Class文件中的常量池,存放编译期生成的各种字面量和符号引用。当然运行时常量也可能计入方法区常量池。典型例子为String.intern()。
可能的问题:
1.基础的内存分配
2.对内存配置参数
3.永久代配置
4.配置堆内存超过实际物理内存
5.NIO(New Input/Output)基于通道和缓冲区可以使用Native方法直接分配堆外内存,通过一个directByteBuffer对象作为引用来操作,某些场景下可以提高性能,减少频繁在java堆和Native堆之间复制数据。