Ⅰ、什么是JVM
- JVM:Java Virtual Machine,JAVA程序运行时的环境。
-
优势:1、一次代码编写,到处运行;2、自动内存管理,垃圾回收机制;3、数组越界检查。
Ⅱ、内存结构
1、整体架构

2、程序计数器
- 作用:用于保存JVM中下一条所要执行的指令的地址;
- 特点:a、线程私有;b、不会存在溢出;
3、虚拟机栈
- 定义:Java虚拟机栈描述的是Java方法执行的内存模型,是每个线程独有的;
- 每个方法执行的时候,Java虚拟机都会同步创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。
- 每个线程当前只能有一个活动栈帧,对应于当前执行的方法。
3.1 问题辨析
- 1、垃圾回收机制是否涉及到栈内存?
- 不涉及。因为虚拟机栈是由一个个栈帧组成的,待方法执行完毕之后,对应的栈帧就会弹栈,所以无需垃圾回收机制;
- 2、栈内存分配越大越好?
- 不一定。在物理内存一定的情况下,如果栈内存分配的越大,当前线程可执行的递归次数相应变大,但是同时存在的线程数目会减少。
- 3、方法内的局部变量是否线程安全?
- 不一定。如果线程的局部变量没有逃离方法的作用范围,是安全的;
- 但是如果线程的局部变量引用了对象,并且逃离了方法的作用范围,是需要考虑线程安全的。
3.2 栈内存溢出
-
Java.lang.stackOverflowError:栈内存溢出; - 原因:1、虚拟机栈中,栈帧过多;2、每个栈帧所占用过大;
4、本地方法栈
- 一些带有native关键字的方法就是需要JAVA去调用本地的C或者C++方法,因为JAVA有时候没法直接和操作系统底层交互,所以需要用到本地方法
5、堆
- 在Java中所有对象的实例化都是在堆中分配内存;
- 所有线程共享,堆内存中的对象需要考虑线程安全问题;
- 有垃圾回收机制。
6、方法区
-
用于存储已经被虚拟机加载的类型的信息、常量、静态变量、即时编译器编译后的代码缓存数据等;
6.1 常量池与运行时常量池
- 常量池就是一张表,虚拟机指令根据这张常量表找到要执行的类名、方法名、参数类型和字面量信息;
- 运行时常量池:运行时常量池是方法区的一部分。常量池是被记录在Class文件中,当类被加载后,这部分内容将被加载到运行时常量池。
6.2 串池(String Table)
- 串池的位置:在JVM1.6中串池位于常量池中,而对于JVM1.8,串池被分配到堆内存当中。
- 利用串池的机制,可以避免重复创建字符串对象;
- 字符串变量的拼接底层是利用了StringBuilder;
- 字符串常量拼接的是在编译阶段编译器进行了优化;
- 可以使用intern方法,主动将串池中还没有的字符串对象放入串池中;
- 在
1.8中调用字符串对象的intern方法,会将该字符串尝试放入到串池中。如果串池中没有该字符串对象,则放入成功;如果串池中存在该字符串对象,放入失败,返回串池中的字符串对象; - 而在
1.6中,会将字符串尝试放入串池中,如果有不会放入,返回串池中的对象;如果没有,会把该对象拷贝一份,放入串池中,并返回串池中的对象。
- 在
6.3 String Table调优
- 由于
StringTable是由HashTable实现的,所以可以适当的增加其中的桶个数,来减少哈希计算时产生的碰撞次数。
7. 直接内存
- 属于操作系统,常见于NIO操作时用于数据缓冲区;
- 分配回收成本高,但是读写性能好;
- 不受JVM内存回收管理。
7.1 文件读写流程

-
使用了DirectBuffer
- 直接内存是操作系统和Java代码都可以访问的一块区域,无需将代码从系统内存复制到Java堆内存,从而提高了读写效率。


