Java性能调优实战
刘超
金山软件西山居技术经理
立即订阅
7535 人已学习
课程目录
已完结 48 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | 怎样才能做好性能调优?
免费
模块一 · 概述 (2讲)
01 | 如何制定性能调优标准?
02 | 如何制定性能调优策略?
模块二 · Java编程性能调优 (10讲)
03 | 字符串性能优化不容小觑,百M内存轻松存储几十G数据
04 | 慎重使用正则表达式
05 | ArrayList还是LinkedList?使用不当性能差千倍
加餐 | 推荐几款常用的性能测试工具
06 | Stream如何提高遍历集合效率?
07 | 深入浅出HashMap的设计与优化
08 | 网络通信优化之I/O模型:如何解决高并发下I/O瓶颈?
09 | 网络通信优化之序列化:避免使用Java序列化
10 | 网络通信优化之通信协议:如何优化RPC网络通信?
11 | 答疑课堂:深入了解NIO的优化实现原理
模块三 · 多线程性能调优 (10讲)
12 | 多线程之锁优化(上):深入了解Synchronized同步锁的优化方法
13 | 多线程之锁优化(中):深入了解Lock同步锁的优化方法
14 | 多线程之锁优化(下):使用乐观锁优化并行操作
15 | 多线程调优(上):哪些操作导致了上下文切换?
16 | 多线程调优(下):如何优化多线程上下文切换?
17 | 并发容器的使用:识别不同场景下最优容器
18 | 如何设置线程池大小?
19 | 如何用协程来优化多线程业务?
20 | 答疑课堂:模块三热点问题解答
加餐 | 什么是数据的强、弱一致性?
模块四 · JVM性能监测及调优 (6讲)
21 | 磨刀不误砍柴工:欲知JVM调优先了解JVM内存模型
22 | 深入JVM即时编译器JIT,优化Java编译
23 | 如何优化垃圾回收机制?
24 | 如何优化JVM内存分配?
25 | 内存持续上升,我该如何排查问题?
26 | 答疑课堂:模块四热点问题解答
模块五 · 设计模式调优 (6讲)
27 | 单例模式:如何创建单一对象优化系统性能?
28 | 原型模式与享元模式:提升系统性能的利器
29 | 如何使用设计模式优化并发编程?
30 | 生产者消费者模式:电商库存设计优化
31 | 装饰器模式:如何优化电商系统中复杂的商品价格策略?
32 | 答疑课堂:模块五思考题集锦
模块六 · 数据库性能调优 (8讲)
33 | MySQL调优之SQL语句:如何写出高性能SQL语句?
34 | MySQL调优之事务:高并发场景下的数据库事务调优
35 | MySQL调优之索引:索引的失效与优化
36 | 记一次线上SQL死锁事故:如何避免死锁?
37 | 什么时候需要分表分库?
38 | 电商系统表设计优化案例分析
39 | 数据库参数设置优化,失之毫厘差之千里
40 | 答疑课堂:MySQL中InnoDB的知识点串讲
模块七 · 实战演练场 (4讲)
41 | 如何设计更优的分布式锁?
42 | 电商系统的分布式事务调优
43 | 如何使用缓存优化系统性能?
44 | 记一次双十一抢购性能瓶颈调优
结束语 (1讲)
结束语 | 栉风沐雨,砥砺前行!
Java性能调优实战
登录|注册

21 | 磨刀不误砍柴工:欲知JVM调优先了解JVM内存模型

刘超 2019-07-09
你好,我是刘超。
从今天开始,我将和你一起探讨 Java 虚拟机(JVM)的性能调优。JVM 算是面试中的高频问题了,通常情况下总会有人问到:请你讲解下 JVM 的内存模型,JVM 的性能调优做过吗?

为什么 JVM 在 Java 中如此重要?

首先你应该知道,运行一个 Java 应用程序,我们必须要先安装 JDK 或者 JRE 包。这是因为 Java 应用在编译后会变成字节码,然后通过字节码运行在 JVM 中,而 JVM 是 JRE 的核心组成部分。
JVM 不仅承担了 Java 字节码的分析(JIT compiler)和执行(Runtime),同时也内置了自动内存分配管理机制。这个机制可以大大降低手动分配回收机制可能带来的内存泄露和内存溢出风险,使 Java 开发人员不需要关注每个对象的内存分配以及回收,从而更专注于业务本身。

从了解内存模型开始

JVM 自动内存分配管理机制的好处很多,但实则是把双刃剑。这个机制在提升 Java 开发效率的同时,也容易使 Java 开发人员过度依赖于自动化,弱化对内存的管理能力,这样系统就很容易发生 JVM 的堆内存异常,垃圾回收(GC)的方式不合适以及 GC 次数过于频繁等问题,这些都将直接影响到应用服务的性能。
因此,要进行 JVM 层面的调优,就需要深入了解 JVM 内存分配和回收原理,这样在遇到问题时,我们才能通过日志分析快速地定位问题;也能在系统遇到性能瓶颈时,通过分析 JVM 调优来优化系统性能。这也是整个模块四的重点内容,今天我们就从 JVM 的内存模型学起,为后续的学习打下一个坚实的基础。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《Java性能调优实战》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(44)

  • 张学磊
    String a="b"可能创建一个对象或者不创建对象,如果"b"这个字符串在常量池里不存在会在常量池创建一个String对象"b",如果已经存在则a直接reference to这个常量池里的对象;
    String c= new String("b")至少创建一个对象,也可能两个,因为用到new关键字,会在堆内在创建一个的String对象,它的值是"b"。同时,如果"b"这个字符串在常量池里不存在,会在常量池创建这个一个String对象"b"。

    作者回复: 对的

    2019-07-09
    21
  • Xiao
    老师,这儿其实应该说JVM内存结构更合适!JVM内存模型是一种规范,和JVM内存结构不是一个概念。其次,元空间,在Java8,不是在堆内分配的,它的大小是依赖于本地内存大小!

    作者回复: 感谢Xiao同学的提醒。

    我想你说的内存模型应该是指Java内存模型(JMM)吧。这里的JVM内存模型跟Java内存模型是不一样的,这里的JVM内存模型和和内存结构是一个意思。

    元空间是分配的本地内存,文中开始描述不清楚(已纠正),但后面有明确说明。

    2019-07-09
    14
  • Liam
    请教一个问题,所以1.8开始,方法区是堆的一部分吗?也即是说,方法区的大小受限于堆

    作者回复: 方法区不是堆的一部分,方法区和堆存在交集。方法区的静态变量和运行时常量池存放在堆中,但类的元信息等还是存放在了本地内存中。

    2019-07-09
    1
    5
  • 我又不乱来
    String a="b"应该会放在字符串常量池中。
    String c= new String("b") 首先应该放在 堆中一份,再在常量池中放一份。但是常量池中有b了。
    第一次留言。不知道理解的对不对。超哥

    作者回复: 正确

    2019-07-09
    5
  • Gred
    老师,运行时变量应该都在方法区中,从java7开始只有字符串常量池移到堆中而已

    作者回复: 严格来说,是静态常量池和运行时常量池,静态常量池是存放字符串字面量、符号引用以及类和方法的信息,而运行时常量池存放的是运行时一些直接引用。

    运行时常量池是在类加载完成之后,将静态常量池中的符号引用值转存到运行时常量池中,类在解析之后,将符号引用替换成直接引用。

    这两个常量池在JDK1.7版本之后,就移到堆内存中了,这里指的是物理空间,而逻辑上还是属于方法区(方法区是逻辑分区)。

    2019-08-02
    3
  • 东方奇骥
    老师,问一下,1.8静态变量和常量存储在的堆里面,那元空间里是什么?文中说之前永久带类的数据存储在了元空间,不是很理解,

    作者回复: 元空间主要存储类的一些信息,包括方法、字段、类等描述类信息。

    2019-07-12
    2
  • 帽子丨影
    元空间的存储位置时本地内存,请问下本地内存是个什么东西,在第一张图里没找到啊。

    作者回复: 本地内存是一种非JVM堆内存

    2019-08-20
    1
  • 发条橙子 。
    老师,这句话怎么理解

    之前永久代的类的元数据存储在了元空间,永久代的静态变量(class static variables)以及运行时常量池(runtime constant pool)则跟 Java7 一样,转移到了堆中。

    方法区的一部分是由永久代实现的,永久代主要存储类的静态数据以及运行时常量池并储存在堆内存中。 但是由于容易发生permen内存溢出,后来就发明了元数据空间。那我理解元空间除了存储之前方法区的类信息还包括之前放在永久代中的 静态变量 和 运行时常量池 。
    文中为什么说和jdk7一样还是转移到堆中,那不是没有变化么?

    作者回复: 是的,没有变化。

    2019-07-20
    1
  • 晓杰
    创建一个线程,就会在虚拟机中申请一个栈帧,这句话有问题吧
    应该是创建一个线程,会创建一个栈,然后方法调用一次,就会申请一个栈帧吧

    作者回复: 对的,这里是申请一个线程栈。

    2019-07-11
    1
  • Cain
    常量池在哪个区?堆区?栈区?方法区?静态区?方法区,静态区他俩是什么关系?

    作者回复: 在逻辑空间是属于方法区。堆、栈、方法区等,这些是一种规范,是逻辑上的分区。

    在物理空间中,常量池是存储在堆内存空间的。

    2019-07-10
    1
  • 黑夜里的猫
    字符串常量不是在java8中已经被放入到堆中了吗,应该不在方法区中了,但是看到老师的图中还在方法区中

    作者回复: 方法区是一个规范,并不是一个物理空间,我们这里说的字符串常量放在堆内存空间中,是指实际的物理空间。

    2019-07-09
    1
  • 听雨
    元空间不是本地内存吗,老师说的元空间移入堆内存是什么意思呀,不理解,是元空间属于堆内存的一部分吗?

    作者回复: 而到了 Java8,永久代被元空间取代了,元空间存储静态变量...

    以上这句话描述不准确。将元空间去掉。元空间是使用的本地内存,在后面讲述到了:“并且元空间的存储位置是本地内存”

    2019-07-09
    1
  • 超威丶
    其实常量池中是不会存储具体对象的吧,也是引用,所以说new String的话会现在常量池中去寻找,存在直接由常量池中的引用指向堆中对象,不存在直接开辟新对象?

    作者回复: 字符串常量存储在了常量池,引用在运行时存放在了栈中。new String("")是会创建一个新对象的,可以查看一下构造函数:
        public String(String original) {
            this.value = original.value;
            this.hash = original.hash;
        }

    2019-07-09
    1
  • TerryGoForIt
    老师您好,我想问一下,深入理解 JIT 放到下一节了嘛?我看课程目录 JIT 是在 JMM 之前哇。

    作者回复: 是的,调换下位置方便更好理解JIT,因为JIT用到了JVM内存的知识点。声明下,这里不是JMM,JMM是Java Memory Model,而我们这节讲的是JVM的内存模型(Java Virtual Machine Structure)。

    2019-07-09
    1
  • 斐波那契
    老师 看完这个 对于运行时常量池和字符串常量池有点搞不清 是不是运行时常量池包括字符串常量池还是说这两个是不同的东西?

    作者回复: 两者有区别,通常方法区中有静态常量池和运行时常量池,静态常量池主要存储的是字面量以及符号引用等信息,而运行时常量池存储的是类运行加载时生成的直接引用等信息。静态常量池也包括了我们说的字符串常量池。

    2019-11-23
  • Malcolm。
    print 静态方法属于 JVMCase 类 JVMCase 类在方法区 所以静态方法也是在方法区是吧
    2019-11-13
  • ZHANG
    老师,是这样吗,java8中类的静态变量,运行时常量池,字符串常量池都在堆中,那元空间只有一些类的信息了,比如版本什么的。
    2019-10-31
  • 谭震弘
    由于 Java 是多线程语言,当执行的线程数量超过 CPU数量

    这里cpu数量不对把,应该是cpu核数?

    作者回复: 对的,此处的数量是指CPU核数

    2019-10-18
  • 丁浪
    你的理解跟我不太一致,说下我的理解。
    jdk7以前,常量池都是存放在方法区,也就是永久代中。jdk7的时候,只是把“字符串常量池”从方法区/永久代中移除了,“运行时字符串”其实还没变的。jdk8的时候,只是用元空间取代了以前的永久代,“字符串常量池”在堆中,“运行时常量”、类的元数据信息等等都在元空间。元空间属于非堆,使用的是本地内存。

    作者回复: 从官方文档解释,class metadata is stored in a new space called Metaspace,所以并没有指出有其他内容存放在元空间。具体的可以参考以下链接:
    https://www.oracle.com/webfolder/technetwork/tutorials/mooc/JVM_Troubleshooting/week1/lesson1.pdf

    2019-10-17
  • godtrue
    课后思考及问题
    1:JVM的内存结构
    1-1:堆——共享,最大,存几乎所有对象和数组,内部有分为年轻代和老年代,年轻代又继续分为E区、S0区、S1区。
    1-2:方法区——共享,是个逻辑分区,8-物理上在堆上分配,存类信息、运行时常量池、静态常量池等信息。8是开辟了部分本地内存,用于存储类信息,常量池信息还在堆上分配。
    1-3:虚拟机方法栈——私有,存储线程的方法调用信息,主要是栈帧。
    1-4:本地方法栈——私有,存储线程的本地方法调用信息,也是主要是栈帧。
    1-5:程序计数器——私有,记录线程的当前执行的位置信息。
    老师,请问线程能创建多少,3/4/5中最小的是一个关键限制因素嘛?这三个区域也有对用的配置参数可调控吧?

    作者回复: 1、根据机器配置环境创建线程数量不一样;2、3/4/5有可能会成为瓶颈,有参数可以调节,例如,使用-Xss 参数设置栈的大小。

    2019-09-11
收起评论
44
返回
顶部