一、程序计数器
记住下一条jvm指令的执行地址,解释器会去程序计数器拿jvm指令。
线程私有的,CPU会给每个线程分配时间片,时间片执行完会切换线程。
唯一不会出现内存溢出的区域。
二、虚拟机栈
线程运行需要的内存空间,每个线程都有一个栈。
由多个栈帧组成,每个方法运行需要的内存(参数、局部变量、返回值),先入后出。
每个线程只能有一个活动栈帧,就是正在执行的方法。
垃圾回收不涉及栈内存。
栈内存参数:-Xss 1024k。栈内存变大,总线程就会变少。
方法内的局部变量如果没有逃离方法的作用范围,则是线程安全的。
栈内存溢出错误:StackOverflowError
案例:
(一)CPU占用过高
1、查看所有进程的cpu占用率,获取哪个进程占用cpu最高:top。
2、查看某个进程的哪个线程占用cpu最高:ps H -eo pid,tid,%cpu | grep ${pid}。
3、查看某个进程的所有线程详细信息:jstack ${pid}。
三、本地方法栈
本地方法运行使用的内存,例如object.clone(),被native修饰的。
四、堆(heap)
通过new创建的对象都会放在堆中,线程共享的,有垃圾回收机制。
内存溢出异常:java.lang.OutOfMemoryError: java heap space。
堆内存参数:-Xmx 8m
堆内存诊断
1、jps:查看当前系统中有哪些Java进程。
jps -l
(netstat -ano | findstr "8848")
2、jmap:查看某进程的堆内存使用情况。堆内存快照信息。
jmap -heap ${pid}
3、jconsole:图形界面,多功能检测工具,可连续监测。
4、jvisualvm:更好用的图形界面工具。
五、方法区
所有线程共享,存储了跟类的结构相关的信息,虚拟机启动时创建。
方法区内存参数:-XX:MaxPermSize=8m
方法区内存溢出异常:java.lang.OutOfMemoryError: Metaspace。(1.8元空间)
java.lang.OutOfMemoryError: PermGen space。(1.6永久代)
1、运行时常量池
二进制字节码(类的基本信息,常量池,类的方法定义,包含了虚拟机指令)
获得虚拟机指令码:javap -v xxx.class
常量池,就是一张表,虚拟机指令根据这张常量表找到要执行的类名、方法名、参数 类型、字面变量等信息。
运行时常量池,常量池是*.class文件中的,当类被加载,它的常量池信息就会放到运行时常量池中,并把里边的符号地址变为真实地址
1.1、StringTable(串池)
运行时常量池中的字符串常量会被放到串池中,通过new关键字创建出的字符串对象不会放入串池。
intern()方法可以将字符串对象尝试放入串池,如果有则不会放入,如果没有则放入,如论是否放入都会返回串池的对象。
例:String x = new String("a") + new String("b");
String s = x.intern();
s是串池的对象。
如果串池中已有“ab”,那么x不会被放入串池,但是s仍会得到串池的“ab”
1.8中,如果串池中没有“ab”,那么x会被放入串池。
1.6中,如果串池中没有“ab”,那么会将x的复制放入串池。
1.2、StringTable位置
1.6时放在永久代中,垃圾回收不及时,需要等老年代内存不足时才会收。
1.8时放在堆内存中。
验证:可以不断产生字符串放入串池,造成内存溢出,看抛出的异常时永久代溢出,还是堆内存溢出(注意:验证堆溢出需要添加参数-XX:-UseGCOverheadLimit。这是一个垃圾回收的限制机制,需要关闭)
1.3、StringTable调优
如果字符串常量很多,可以调大StringTable桶的数量:-XX:StringTableSize=20000
六、直接内存
操作系统的内存,不受Java虚拟机管理。
常见于NIO操作时,用于数据缓冲区。
分配回收成本较高,但读写性能高。
不受JVM内存回收管理。
直接内存溢出异常:java.lang.OutOfMemoryError: Direct buffer Memory。