jvm内存分区

1.程序计数器

  • 作用,记住下一条指令的地址
  • 通过寄存器实现
  • 特点
    • 线程私有
    • 不会存在内存溢出

2.jvm虚拟机栈

2.1 定义

  • 栈帧默认1MB

  • 每个线程运行需要的内存,成为虚拟机栈
  • 每个栈由多个栈帧(Frame)组成,对应着每次调用所占的内存
  • 每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法

2.2 栈内存溢出

问题辨析:

1.垃圾回收是否涉及栈内存?

​ 没有,栈内存在执行完之后自动弹出栈顶销毁。

2.栈内存分配是否越大越好?

​ 不是,因为内存一定,过大的栈内存会减少线程数。

3.方法内的局部变量是否线程安全?

  • 如果方法内局部变量没有逃离方法的作用域,是线程安全的
  • 如果局部变量引用了对象,并逃离方法的作用域,就需要考虑线程安全

4.什么情况会导致栈溢出(使用-Xss设置栈大小)

  • 栈帧过多
  • 栈帧过大

特殊情况:json时出现对象循环引用

解决方法:@JsonIgnore

2.3 线程运行诊断

1.cpu占用过多

先用top命令查看占用cpu过多的进程,再用ps H -eo pid,tid,%cpu grep 进程id 命令查看占用过多cpu的线程,执行jstack 进程id命令查看进程中线程的详细情况,用得到的线程id转化成16进制去对应线程情况中的线程id

2.迟迟等不到结果

jstack进程id命令查看是否有死锁

3.本地方法栈

本地方法栈(Native Method Stacks)与虚拟机栈所发挥的作用是非常相似的,其区别只是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的本地(Native)方法服务。

《Java虚拟机规范》对本地方法栈中方法使用的语言、使用方式与数据结构并没有任何强制规定,因此具体的虚拟机可以根据需要自由实现它,甚至有的Java虚拟机(譬如Hot-Spot虚拟机)直接就把本地方法栈和虚拟机栈合二为一。与虚拟机栈一样,本地方法栈也会在栈深度溢出或者栈扩展失败时分别抛出StackOverflowError和OutOfMemoryError异常。

4.堆

4.1 定义

包含了所有new创建的对象。Java堆既可以被实现成固定大小的,也可以是可扩展的,不过当前主流的Java虚拟机都是按照可扩展来实现的(通过参数-Xmx和-Xms设定)。如果在Java堆中没有内存完成实例分配,并且堆也无法再扩展时,Java虚拟机将会抛出OutOfMemoryError异常。

4.2 堆内存诊断

  1. jps工具

    查看当前系统中有哪些java进程

  2. jmap工具

    jmap -heap 进程id,查看堆内存占用情况

  3. jconsole

    图形界面的,多功能的检测工具,能连续检测

4.3 StringTable

String a = “a”;

String b = “b”;

下面经过编译优化相当于String c = “ab”;

String c = “a” + “b”;

下面在堆中创建了两个String,一个StringBuilder对象,在StringTable中创建了”a”,”b”两个字符串,没有”ab”字符串

String s = new String(“a”) + new String(“b”);

调用s.intern(),将”ab”放入StringTable,如果StringTable有”ab”字符串,则直接放回”ab”的地址,否则返回新放入的”ab”的地址

总结,如果字符串拼接的时候含有String变量,都会通过StringBuilder对象完成拼接,且拼接后的结果不会放入StringTable中。

5. 方法区

jdk1.8由metaspace实现,它用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。如果方法区无法满足新的内存分配需求时,将抛出OutOfMemoryError异常。

oom的情况:Cglib反射创建很多个代理子类的时候,会出现oom

使用-XX:MaxMetaspaceSize=8m可以设置元空间的最大大小

原始链接 版权声明:自由转载-非商用-非衍生-保持署名 | Creative Commons BY-NC-ND 4.0