JVM笔记

JVM

为什么要学习Jvm,学习Jvm可以干什么?

jvm为程序分配内存

JVM、JRE、JDK关系

JDK包含Jre、jre包含Jvm

jdk除jre、jvm外,还包含编译文件和对jvm信息进行监控

jre用来运行的基础环境,jvm编译class为文件,适配各操作系统

JVM运行时数据层区分?在这里插入图片描述

方法区:用于存放类信息、常量、静态变量以及编译后的代码。

堆(唯一作用):用于存放对象实例。

程序计数器(线程计数器):用来记录线程当前执行的行号,程序计数器之间互不影响。

本地方法栈:为虚拟机执行方法提供服务(C、C++代码)

虚拟机栈:生命周期同线程,一个方法绑定一个栈帧,栈帧存放局部变量、操作数栈、动态链接、出口。

能手动回收垃圾?

不能,能建议jvm进行垃圾回收,但是不能控制jvm何时进行垃圾回收

堆被分为新生代和老年代?

新生代:老年代=1:2

Eden:From Survivor:ToSurvivor=8:1:1

JVM 每次只会使用 Eden 和其中的一块 Survivor 区域来为对象服务,所以无论什么时候,总是有一块 Survivor 区域是空闲着的。

Minor GC、Major GC、Full GC区别及触发条件?

  • Minor GC新生代GC,用来回收新生代

触发条件:Eden区域满了或者新的新生代所需空间大于Eden现有空间

  • Major GC老年代GC,用来回收老年代

存活的新生代占用空间>老年代剩余空间

老年代空间满了

晋升老年代的新生代对象所需空间的平均大小>老年代剩余空间

执行system.gc()

CMS GC异常

堆内存分配很大的对象

怎么判断对象存活?

  • 引用计数法
  • 可达性分析
  • 标记-清除法
  • 标记-整理法
  • 复制法
  • 分代算法
    • 新生代用复制
    • 老生代用标记-清除法和标记整理法

什么是垃圾收集器?

Serial:复制法(单线程)

ParNew:复制法(多线程)

Parallel Scavenge:复制法(可控制吞吐量)

CMS:标记清除算法

Serial Old:标记-整理法(单线程)

Parallel Old:标记-整理法(多线程)

G1(复制法和标记-整理法):优化后的标记-清除法,可以同时作用与老年代和新生代,适用大内存、多处理器机器

  • 搭配

在这里插入图片描述

JVM参数配置

#常用的设置
-Xms:初始堆大小,JVM 启动的时候,给定堆空间大小。 

-Xmx:最大堆大小,JVM 运行过程中,如果初始堆空间不足的时候,最大可以扩展到多少。 

-Xmn:设置堆中年轻代大小。整个堆大小=年轻代大小+年老代大小+持久代大小。 

-XX:NewSize=n 设置年轻代初始化大小大小 

-XX:MaxNewSize=n 设置年轻代最大值

-XX:NewRatio=n 设置年轻代和年老代的比值。如: -XX:NewRatio=3,表示年轻代与年老代比值为 1:3,年轻代占整个年轻代+年老代和的 1/4 

-XX:SurvivorRatio=n 年轻代中 Eden 区与两个 Survivor 区的比值。注意 Survivor 区有两个。8表示两个Survivor :eden=2:8 ,即一个Survivor占年轻代的1/10,默认就为8

-Xss:设置每个线程的堆栈大小。JDK5后每个线程 Java 栈大小为 1M,以前每个线程堆栈大小为 256K。

-XX:ThreadStackSize=n 线程堆栈大小

-XX:PermSize=n 设置持久代初始值	

-XX:MaxPermSize=n 设置持久代大小
 
-XX:MaxTenuringThreshold=n 设置年轻带垃圾对象最大年龄。如果设置为 0 的话,则年轻代对象不经过 Survivor 区,直接进入年老代。

#下面是一些不常用的

-XX:LargePageSizeInBytes=n 设置堆内存的内存页大小

-XX:+UseFastAccessorMethods 优化原始类型的getter方法性能

-XX:+DisableExplicitGC 禁止在运行期显式地调用System.gc(),默认启用	

-XX:+AggressiveOpts 是否启用JVM开发团队最新的调优成果。例如编译优化,偏向锁,并行年老代收集等,jdk6纸之后默认启动

-XX:+UseBiasedLocking 是否启用偏向锁,JDK6默认启用	

-Xnoclassgc 是否禁用垃圾回收

-XX:+UseThreadPriorities 使用本地线程的优先级,默认启用	

等等等......

JVM的GC收集器设置

-XX:+UseSerialGC:设置串行收集器,年轻带收集器 

 -XX:+UseParNewGC:设置年轻代为并行收集。可与 CMS 收集同时使用。JDK5.0 以上,JVM 会根据系统配置自行设置,所以无需再设置此值。

-XX:+UseParallelGC:设置并行收集器,目标是目标是达到可控制的吞吐量

-XX:+UseParallelOldGC:设置并行年老代收集器,JDK6.0 支持对年老代并行收集。 

-XX:+UseConcMarkSweepGC:设置年老代并发收集器

-XX:+UseG1GC:设置 G1 收集器,JDK1.9默认垃圾收集器

类加载器

启动类加载器(BootStrap)

加载Java_home/jre/lib/rt.jar下的的所有类

拓展类加载器(ExtClassLoader)

加载Java_home/bin/ext下的类库

系统类加载器(AppClassLoader)

父类加载器为ExtClassLoader

自定义加载器()

父类加载器为AppClassLoader

双亲委派机制

**原理:**双亲委派机制,其工作原理的是,如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行,如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器,如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式,即每个儿子都很懒,每次有活就丢给父亲去干,直到父亲说这件事我也干不了时,儿子自己才想办法去完成。

**优势:**采用双亲委派模式的是好处是Java类随着它的类加载器一起具备了一种带有优先级的层次关系,通过这种层级关可以避免类的重复加载,当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次。其次是考虑到安全因素,java核心api中定义类型不会被随意替换,假设通过网络传递一个名为java.lang.Integer的类,通过双亲委托模式传递到启动类加载器,而启动类加载器在核心Java API发现这个名字的类,发现该类已被加载,并不会重新加载网络传递的过来的java.lang.Integer,而直接返回已加载过的Integer.class,这样便可以防止核心API库被随意篡改。

到安全因素,java核心api中定义类型不会被随意替换,假设通过网络传递一个名为java.lang.Integer的类,通过双亲委托模式传递到启动类加载器,而启动类加载器在核心Java API发现这个名字的类,发现该类已被加载,并不会重新加载网络传递的过来的java.lang.Integer,而直接返回已加载过的Integer.class,这样便可以防止核心API库被随意篡改。

### 关于JVM的学习资源 对于希望深入学习 Java 虚拟机 (JVM) 的开发者来说,《黑马程序员 JVM 完整教程》是一份非常有价值的入门材料[^1]。这份笔记涵盖了 JVM 基础概念、内存模型以及性能调优等内容,适合初学者快速掌握 JVM 的核心知识点。 如果需要更深层次的理解,可以参考以下书籍: 1. **《深入理解 Java 虚拟机:Jvm 高级特性与最佳实践(第 2 版)》** 这本书详细讲解了 JVM 的内部机制,包括类加载过程、垃圾回收算法、性能优化策略等高级主题。它不仅提供了丰富的理论知识,还通过实际案例帮助读者解决常见的 JVM 性能问题。 2. **《实战 Java 虚拟机》** 此书侧重于 JVM 实战技巧,特别适用于那些希望通过真实项目经验提升技能的技术人员。书中包含大量实用工具和技术的应用场景分析。 3. **《深入 JAVA 虚拟机第二版》** 另一本经典著作,专注于 JVM 架构设计及其运行原理,能够为开发者的日常编码提供指导和支持。 除了上述书籍外,在线还有许多免费资源可供利用。例如官方文档总是最好的起点之一;另外像 Oracle 提供的各种技术白皮书也是不可多得的好资料。 需要注意的是,当涉及到并发编程时,了解重排序现象非常重要。因为即使代码按特定顺序编写出来,编译器或者处理器为了提高效率可能会改变它们的实际执行次序——只要这种变化不会影响单线程环境下的最终结果即可[^2]。 至于方法实现方面,则需确保函数签名中的返回类型同其逻辑体内的最后一句`return`表达式的类别相一致。否则将会引发编译错误[^3]。 以下是基于这些原则的一个简单示例展示如何判断一个数是否偶数并找出两个数值之间的较大者: ```java public class Example { public static void main(String[] args){ System.out.println(isEvenNumber(4)); // 输出true System.out.println(getMax(8,5)); // 输出8 } public static boolean isEvenNumber(int number ){ return ((number % 2)==0); } public static int getMax(int a,int b){ if(a>b) return a; else return b; } } ``` ####
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值