JVM
优点:
- 一次编译到处运行
- 自动垃圾回收机制
- 自动数组下边越界检测
程序计数器
作用:
记录JVM指令执行内存地址
特点:
- 线程私有
- 不存在内存溢出问题
虚拟机栈
特点:
- 栈为线程运行需要的内存空间
- 一个栈由一个或多个栈帧组成,栈帧的执行顺序为先入后出(对应java代码方法执行情况,方法1调用方法2 结果为方法2后入栈但是先执行完毕)
- 栈帧为方法运行所需的内存空间,包含方法参数、局部变量、返回地址
- 每个线程执行时只能存在一个活动的栈帧(对应正在执行的方法)
进阶
- 垃圾回收机制不会回收栈内存,垃圾回收机制是回收堆内存,而栈内存会跟随线程的执行自动回收
- 栈内存并不是设置的越大越好,因为物理内存是固定的,如果栈内存设置过大,会导致程序可用线程变少
- 设置栈内存大小可使用 -Xss=1m linux mac 默认大小都是1m
- 方法内的变量是否线程安全,主要取决与变量的作用域范围,如果仅为当前方法可以使用则为线程安全
- 栈内存溢出(stackOverFlowError)出现原因:
- 栈内栈帧过多,一般发生在递归调用
- 栈内栈帧过大,栈帧大小超过了栈内存大小
- cpu占用过高问题定位:
- 使用 top命令查看占用cpu过高的进程
- 使用 ps H -eo pid,tid,%cpu | grep 进程id 找到进程中占用cpu最多的线程
- 使用JVM提供的工具 jstack 进程id 查看线程信息
- 将线程id转换为十六进制 找到对应线程信息 查看代码出现问题行数
- 线程死锁:
- 使用jstack 进程id 查看线程信息
- 信息最后会显示 查到一个死锁,再查看导致死锁线程的信息定位到实际代码
本地方法栈
为由C编写的代码运行提供的一个内存空间,由**Native **修饰的方法
堆
特点
- 堆内存是线程共享的,堆中的对象需要考虑线程安全问题
- new 出来的对象都在堆内存中
- 堆内存由垃圾回收机制来维护内存
进阶
- 内存溢出(outOfMemery)
- 通过 -Xmx500m 设置堆内存最大值
- 通过 -Xms200m设置堆内存最小值
- 排查内存问题:
- 可以使用jconsole jvm自带可视化工具
- 可以使用jmap -heap 进程id 获取堆内存快照
- 可以使用第三方工具JVisualVM、JProfiler 来实现
方法区:
特点:
- 方法区主要用来存放 class classLoader 运行时常量池
- 是线程共享的内存区域,意味这所有线程都可以访问方法区中的数据
- JDK1.8后默认大小是系统物理内存大小,没有设置上限,可以使用命令 -XX:MaxMetaspaceSize设置方法区大小,并且由方法区由永久代变成本地内存中的元空间,垃圾回收变成 native memory 中来完成,但还是由gc来完成
- 在jdk1.8之前版本方法去被设置为永久代,永久代大小默认为64M,可以通过**-XX:MaxPermSize**选项进行设置,并且1.7之前方法区的垃圾回收是FULL GC
问题:
- 内存溢出:
- 当类比较多,并且系统内存较小或者方法区内存设置太小,1.8后会报OutofMemoryError:MetaSpace元空间内存溢出,1.8之前报OutofMemoryError:PermGen space永久代内存溢出
常量池:
特点:
- 在的jdk1.6之前常量池在永久代也就是方法区
- jdk1.7将常量池在堆中
- jdk1.8常量池放在元空间(方法区由永久代改为元空间,删除了永久代),但是字符串常量池还是在堆中,其他常量存放在方法区也就是元空间
StringTable(字符串常量值)
字符串常量值在JVM内部是通过hashTable 来实现的,当程序执行过程中出现一个字符串字面量,就会先去查找是否存在,如果存在直接返回引用,不存在则将新值写入StringTable
定义:
- 常量池中的字符串仅是一种符号只有再用到是才会变成对象
- 利用字符串持机制避免重复创建字符串对象,从而节省空间
- 字符串变量的拼接原理使用StringBuilder.append()
- 字符串常量拼接是在编译器优化
- 使用intern()方法可以主动将字符串常量池中没有的对象,放入字符串常量池
调优:
- stringTable 在jvm中是由hashTable来实现的,而hashTable底层是由数组加链表来完成,如果hashTable size 比较小而常量比较多的情况下,平均分配的每个数组元素下链表的节点也就会比较多,查找起来也就相会变慢,所以 我们可以通过命令 -XX:StringTableSize=size个数来设置Hashtable的size大小,减小分配到每个链表的节点个数
- 当程序中存在大量的字符串时,可以考虑使用用 String 的intern()方法入串池,减少堆内存占用。
JDK JVM版本对比图
评论
0 评论