上篇文章:java虚拟机面试干货【贰】_类的加载
本文说说JVM的内存结构,主要分为6个区域:
程序计数器
可看做是当前线程执行的字节码的行号指示器,字节码解释器就是通过改变这个计数器的值来获取下一条需要执行的字节码指令,完成分支、循环、跳转和异常处理等功能。
虚拟机栈
每创建一个线程时,JVM就会为这个线程创建一个对应的栈,所以栈是线程私有的。方法执行的时候还会创建一个栈帧在虚拟机栈上,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。局部变量表所需的空间在编译期间就完成了分配。
本地方法栈
基本同虚拟机栈,只不过本地方法栈是为本地方法服务。
java堆
JVM管理的内存最大的部分,线程共享,用于存放对象实例。java堆可以处于物理上不连续的内存空间上。用-Xms表示堆起始内存大小,-Xmx表示堆最大内存大小。当堆内存大小大于-Xmx时抛出OutOfMemoryError异常。
方法区
存储已被JVM加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。在Hotspot实现中,它位于java堆上。可称为永久代(PermGen),使用-XX:MaxPermGen参数配置永久代最大内存。
运行时常量池
方法区的一部分。在class文件被JVM加载后,其常量池中的字面量和符号引用将被保存到这里。
在JVM运行中,当分配的内存不够时候有可能抛出如下异常:
StackOverflowError:线程请求的栈深度大于虚拟机锁允许的深度(-Xss)时;
OutOfMemoryError : 如果虚拟机栈空间可以动态拓展,拓展无法获取足够内存时;
OutOfMemoryError : Java heap space:堆内存不足时;
OutOfMemoryError : PernGen space:运行时常量池溢出。String常量对象会在常量池中以hash方式存储和访问,这个hash表默认大小为1009,string常量池里也包含了类名、方法名、属性名等信息。可修改-XX:StringTableSize来增加hash元素个数;
IOException : Too many open files : 可能是socket打开过多;
逃逸分析
常用的对象堆外存储技术需要基于逃逸分析(Escape Analysis)技术实现。其目标就是分析出对象的作用域。比如当一个对象定义在方法体内部时,它的受访范围就在方法体内,jvm会在栈帧中为其分配内存空间。但一旦被外部成员引用后,这个对象就发生了逃逸。
在JDK 6u23后,HotSpot就默认开启了逃逸分析,早期版本可用-XX:+DoEscapeAnalysis参数开启,-XX:+PrintEscapeAnalysis查看。
下篇文章说收垃圾回收