1.程序计数器
1.1定义
program counter register 程序计数器(寄存器)
1.2作用
记住下一条指令的执行地址。
二进制字节码前面的数字相当于执行地址
当执行第一条指令时他会把下一条指令的地址放在程序计数器中,程序计数器相当于一个寄存器。
1.3特点
是线程私有的。
不会存在内存溢出。
2.虚拟机栈
2.1定义
Java Virtual Machine Stacks(java虚拟机栈)
- 每个线程运行时所需要的内存,称为虚拟机栈
- 每个栈由多个栈帧组成
- 每个线程只能有一个活动栈帧,对应者当前正在执行的那个方法
(活动栈帧,栈顶部的,表示该线程正在执行的那个方法)
一个栈有内存空间组成
栈帧:java运行时每个方法所需要的内存我们 就称之为栈帧
(方法里的参数,局部变量,返回地址都需要内存)
问题辨析
1.垃圾回收是否涉及栈内存?
不需要。栈内存无非就是一次次方法调用所产生的,而栈帧随着方法的调用都会被弹出栈,释放空间。
2.栈内存分配越大越好嘛?
栈内存可以通过运行代码时 JVM参数来指定。
栈内存分的越大,反而会使线程数变少。
3.方法内的局部变量是否线程安全?
- 如果方法内的局部变量没有逃离方法的作用范围,他是线程安全的。
反之,如果当中返回值返回了,就不安全 - 如果是局部变量引用了对象,并且逃离了方法的作用范围,需要考虑他的线程安全。
栈是线程私有的。
局部变量存储在栈中,类的static成员变量在方法区,一个线程私有,一个线程共享。
2.2栈内存溢出
导致栈内存溢出的原因:
- 栈帧过多。(比如递归调用,没有有效的边界就很容易溢出)、
- 栈帧过大。
2.3线程运行诊断
案例1:cpu占用过多
案例2:程序运行很长时间没有结果
3.本地方法栈
本地方法就是值那些不是由java代码编写的代码,java代码有限制,有事侯不能直接和操作系统打交道。所以用C/C++来编写本地方法。
本地方法栈就是给本地方法的运行提供内存空间
4. 堆
4.1定义
堆(Heap)
- 通过new 关键字创建的对象都会使用堆内存
- 它是线程共享的,堆中对象都要考虑线程安全问题
- 有垃圾回收机制
4.2堆内存溢出
堆里面有垃圾回收机制,当一个对象不被使用了,就可以视为垃圾被回收,所占的内存就会释放,为什么还会有溢出?
:当作垃圾被回收的条件是没人使用他了,但如果我不断的产生对象,产生的对象一直有人在使用,意味着这些对象不能被当为垃圾,这样的对象达到一定的数量后,就会溢出。
实例:
程序一直执行,一直在list.add(a).得不到释放
堆空间大小参数:-Xmx
(平时我们可以把堆内存设置的小一点,这里可能会尽早的爆露出可能引起堆内存溢出的问题)
4.3堆内存溢出的诊断
(对应视频-19 还要再看)
1.jps工具
查看当前系统中有哪些java进程
2.jmap 工具
3.jconsole 工具
控制台输入 jconsole
案例:
垃圾回收后,内存占用仍然很高。
工具:jvisualvm
演示查看对象个数 使用 堆转储 dump
5.方法区
是jvm的规范,并不是实现。方法区的实现是由永久代或者元空间来实现。
5.1 组成
1.6利用永久代来实现
由于方法区主要存储类的相关信息,所以对于动态生成类的情况比较容易出现永久代的内存溢出。最典型的场景就是,在 jsp 页面比较多的情况,容易出现永久代内存溢出
1.8以后利用元空间实现,不占用堆内存了,使用本地内存。
元空间的本质和永久代类似,都是对JVM规范中方法区的实现。不过元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制,但可以通过以下参数来指定元空间的大小:
-XX:MetaspaceSize,初始空间大小,达到该值就会触发垃圾收集进行类型卸载,同时GC会对该值进行调整:如果释放了大量的空间,就适当降低该值;如果释放了很少的空间,那么在不超过MaxMetaspaceSize时,适当提高该值。
-XX:MaxMetaspaceSize,最大空间,默认是没有限制的。
除了上面两个指定大小的选项以外,还有两个与 GC 相关的属性:
-XX:MinMetaspaceFreeRatio,在GC之后,最小的Metaspace剩余空间容量的百分比,减少为分配空间所导致的垃圾收集
-XX:MaxMetaspaceFreeRatio,在GC之后,最大的Metaspace剩余空间容量的百分比,减少为释放空间所导致的垃圾收集
5.2方法区内存溢出
一些常见的溢出
- spring
- mybatis
(中有很多的动态加载类,使用不当很容易导致内存溢出)
5.3常量池和运行时常量池
5.4String Table
5.5StringTable的位置
jdk1.8把StringTable放在了堆中,更容易触发垃圾回收。
-Xmx10m 设置虚拟机堆内存的参数,此时将堆内存设置为10m。
5.6StringTable的垃圾回收
当内存空间不足时,stringtable中那些没有被引用的字符串常量也会被垃圾回收。
-XX:+PrintStringTableStatistics 打印字符串表的参数
-XX:+PrintGCDetails -verbose:gc 打印垃圾回收的详细信息
5.7StringTable性能调优
StringTable是一个哈希表,哈希表的性能和他的大小是密切相关的。
1.stringtable的大小
jvm默认桶的大小:
修改参数,添加桶的个数(最小值为1009)
如果你的系统中字符串常量的个数很多,通过增加stringtable桶的个数,使它有一个好的哈希分布,减少哈希冲突。
2.考虑将字符串对象是否入池。
运用intern方法将字符串入池,保证相同的字符串只存储一份(在串池中如果已经有相同的字符串对象就不会再创建该字符串对象了)。
6.直接内存
6.1定义
Direct Memory 不是jvm内存,而是我们的系统内存
-
常见于NIO操作时,用于数据缓冲区
-
分配回收成本高,但读写性能高
可以调用allocateDirect(),在操作系统上直接划分一个直接内存,供读写使用。相比第一种少了复制缓冲区的操作,速度就更加快了。 -
不受JVM内存回收管理,但是仍会内存溢出