1.JVM内存结构
jvm的内存空间可分为5个部分:程序计数器,Java虚拟机栈,本地方法栈,方法区,堆。
程序计数器(线程私有): 程序计数器是一个较小的内存区域,主要用来记录各个线程执行的字节码的地址。
Java虚拟机栈(线程私有): JVM 中用于描述 Java 方法运行过程的内存模型 。每当一个 Java 方法被调用时,JVM 会为其创建一个称为"栈帧"的区域,以存储该方法执行过程中的相关信息。方法运行完后会被清空。
本地方法栈(线程私有): 用于支持 Java 程序调用本地方法(Native Method)。本地方法是用其他语言(如 C 或 C++)编写的方法。
方法区(所有线程共享)/(以前都叫永久代): 方法区用于存储JVM加载的类信息、常量、静态变量等数据。它是所有线程共享的内存区域。
堆(所有线程共享): 堆是Java虚拟机所管理的内存中最大的一块存储区域。堆内存被所有线程共享。主要存放对象信息和数组。所有对象实例以及数组都要在堆上分配。垃圾收集器就是根据GC算法,收集堆上对象所占用的内存空间(收集的是对象占用的空间而不是对象本身)。
2.垃圾回收机制(GC):
堆有很多对象使用过后是需要清理的,java引用了GC垃圾回收,当Java虚拟机发觉内存资源紧张的时候,
就会自动地去清理无用对象所占用的内存空间。如果需要,可以在程序中显式地使用System.gc()来
强制进行一次立即的内存清理。
工作原理:
JVM 的垃圾回收机制中,虚拟机会根据可达性分析判断一个对象可达,对于不可达的对象 会被判断
为可回收的对象进行回收处理
3.JVM调优的方法:
1:建议用64位操作系统 Linux下64位的jdk比32位jdk要慢一些,但是吃得内存更多,吞吐量更大。
2:XMX(最大堆内存大小)和XMS(初始堆内存大小)设置一样大,MaxPermSize和MinPermSize设置一样大,这样可以减轻伸缩堆大小带来的压力。
3:调试的时候设置一些打印参数,如-XX:+PrintClassHistogram -XX:+PrintGCDetails
XX:+PrintGCTimeStamps -XX:+PrintHeapAtGc -Xloggc:log/gc.log,这样可以从gc.log里看出
一些端倪出来。
4:系统停顿的时候可能是GC的问题也可能是程序的问题,多用jmap和jstack查看,或者killall -3
java,然后查看java控制台日志,能看出很多问题。有一次,网站突然很慢,jstack一看,原来是自
己写的URLConnection连接太多没有释放,改一下程序就
5:仔细了解自己的应用,如果用了缓存,那么年老代应该大一些,缓存的HashMap不应该无限制
长,建议采用LRU算法的Map做缓存,LRUMap的最大长度也要根据实际情况设定。
6:垃圾回收时promotion failed是个很头痛的问题,一般可能是两种原因产生,第一个原因是救助
空间不够,救助空间里的对象还不应该被移动到年老代,但年轻代又有很多对象需要放入救助空间
;第二个原因是年老代没有足够的空间接纳来自年轻代的对象;这两种情况都会转向FuGC,网站
停顿时间较长。第一个原因我的最终解决办法是去掉救助空间,设置-XX:SurvivorRatio=65536
XX:MaxTenuringThreshold=0即可,第二个原因我的解决办法是设置
CMSInitiatingOccupancyFraction为某个值(假设70),这样年老代空间到70%时就开始执行
CMS,年老代有足够的空间接纳来自年轻代的对象。
7:不管怎样,永久代还是会逐渐变满,所以隔三差五重起java服务器是必要的,我每天都自动重
起
8:采用并发回收时,年轻代小一点,年老代要大,因为年老大用的是并发回收,即使时间长点也不
会影响其他程序继续运行,网站不会停顿。
4.堆和栈的区别:
Java堆和栈是Java虚拟机(JVM)中的两个重要概念,它们在内存管理、存储对象和执行线程等方面有明显的区别。
- 内存分配:
堆:内存手动分配和释放(或垃圾回收)。堆的大小可以在运行时动态调整,通过JVM参数进行配置。。
栈: 自动分配和释放
- 生命周期:
堆:堆的生命周期与应用程序的启动和结束相同。当应用程序启动时,堆被创建;当应用程序结束时,堆随之销毁。垃圾回收器自动管理堆内存的回收和释放。
栈:函数调用结束时自动销毁。
- 空间大小
栈的空间大小远远小于堆的。
- .共享性不同
栈内存是线程私有的。 堆内存是所有线程共有的。
- 存储内容:
堆 :堆主要用于存储对象实例。堆是由垃圾回收器自动管理的,当一个对象不再被引用时,垃圾回收器会自动回收该对象占用的堆内存。
栈 :栈主要存储基本数据类型、对象引用地址和方法的局部变量。
5.JVM使用命令:
java 用于启动 Java 程序。
//启动程序
java HelloWorld
//最大堆内存为 512M
java -Xmx512m HelloWorld
javac 用于编译 Java 源代码文件。
//编译
javac HelloWorld.java
jps 查看当前正在运行的 Java 进程
jps
jstack 打印指定 Java 进程的线程堆栈信息
//查看进程 ID 为 12345 的 Java 进程的线程堆栈
jstack 12345
jmap 查看 Java 堆内存信息或生成堆 dump 文件
//查看进程 ID 为 12345 的 Java 程序的堆内存使用情况
jmap -heap 12345
jstat 查看 JVM 的性能统计信息
//查看进程 ID 为 12345 的垃圾回收(GC)统计信息
jstat -gc 12345
面试题一天五道,持续更新中。。。。。