读Java性能权威指南(第2版)
文章平均质量分 85
读Java性能权威指南(第2版)笔记、感想与总结
躺柒
书既可以读薄也可以读厚
1. 输出才能检验输入;
2. 分享才能集思广益;
3. 完成才能完善,无限完善才能逼近完美;
4. 万事开头难,坚持更难,长期坚持难上加难。
展开
专栏收录文章
- 默认排序
- 最新发布
- 最早发布
- 最多阅读
- 最少阅读
-
Java性能权威指南(第2版)读后总结与感想
语言在不断进化发展、jvm也在不断进化发展,在采用java 8 不变的情况下,使用包含新的垃圾回收算法的jdk,使用新的垃圾回收算法能够获得更好的性能体验。了解不难,学精很难,性能调优不仅仅是技术活,更是一门艺术,需要考虑的场景、判断的条件纷繁复杂,各种开关也会相互影响,使用的不好,还不如采用默认方式。验证、测试自然少不了各种工具,既有原生自带的,也有开源或者商业的第三方工具,在这个方面,介绍的也较详细,能够帮忙我们分析性能问题的源头。有些性能建议是包治百病的,比如,使用更小的对象;原创 2023-04-08 06:30:00 · 205 阅读 · 0 评论 -
读Java性能权威指南(第2版)笔记01_导言
一些芯片制造商称之为核心内的硬件线程(hardware strands within a core)数据库和其他后端系统的性能同JVM一样重要。AMD(和其他厂商)则使用同时多线程。垃圾回收很大程度上是CPU密集型任务。超线程是Intel常用的术语。测试工具也是最有可能出问题的。JVM只是整体性能的一小部分。布尔标志和附带参数的标志。附带参数的标志使用的语法。转载 2023-02-25 07:15:00 · 158 阅读 · 0 评论 -
读Java性能权威指南(第2版)笔记02_ Java SE API技巧上
千万不要在循环中使用字符串连接,除非连接的字符串不会在循环的下一次迭代中使用。当你转到一个较新的版本时,不需要重新编译旧代码,因为字节码会是一样的。String类的intern()方法来创建字符串的标准化版本。想用新的编译器编译出新的代码,以使用新的语言特性。例外是应用程序中所有的字符串都需要16位编码。String.equals()方法是相当快的。JDK 8的优化在处理字符串和整数时效果很好。使用String类的intern()方法。自定义方法来创建字符串的标准化版本。G1 GC执行自动去重。转载 2023-02-26 07:15:00 · 177 阅读 · 0 评论 -
读Java性能权威指南(第2版)笔记03_ Java SE API技巧中
要验证类是否从共享存档加载,可以在命令行加上类加载日志(-Xlog:class+load=info)命令。只适用于从模块或JAR文件加载的类,不能共享(或加速加载)来自文件系统或网络URL的类。某个应用程序是用Java编写的,那么出于性能原因调用原生代码几乎总是一个坏主意。对于文件和套接字,压缩和字符串编码的操作,必须适当地对I/O进行缓冲。编写尽可能快的代码感兴趣,应该避免使用Java原生接口。想要真正快速的代码,应该使用原生代码。使用字符(字符串)数据的文件I/O。常规的CDS(共享默认的JDK类)转载 2023-02-27 07:15:00 · 145 阅读 · 0 评论 -
读Java性能权威指南(第2版)笔记04_ Java SE API技巧下
即使一个对象的所有字段都是瞬时的,最好还是实现Serializable接口并调用defaultWriteObject()方法。通过writeObject()方法和readObject()方法进行的其他优化可以大幅加快序列化的速度。对于频繁创建的系统异常,JVM会优化获取栈轨迹的性能开销。一种将对象的二进制状态写出来,以便之后重新创建的方法。多个过滤器是有开销的,要确保编写性能良好的过滤器。降低对象序列化成本的方法是序列化更少的数据。HashMap用于访问一段随机的数据。集合的大小会对性能产生很大的影响。转载 2023-02-28 07:15:00 · 146 阅读 · 0 评论 -
读Java性能权威指南(第2版)笔记05_数据库性能JDBC
第一个事务可能会回滚(写入操作没有实际发生),因此第二个事务会在错误的数据上操作。一个事务重新执行使用某个WHERE子句的查询时,第二次可能会得到不同的数据。事务的开始和结束都基于Connection对象的使用方式。一个事务可以读取在另一个事务中写入(但未提交)的数据。应用程序对正确性的要求最终决定了事务的处理方式。自动将隔离级别设置为它支持的下一个更严格的级别。规则1:让应用程序中的每个线程都有一个连接。依赖数据库服务器来完成更多的处理工作。必须在每个连接的基础上进行池化。初始化连接对象的成本很高。转载 2023-03-01 07:15:00 · 208 阅读 · 0 评论 -
读Java性能权威指南(第2版)笔记06_数据库性能JPA&SpringData
除非正在使用的JPA实现支持查询缓存,否则使用JOIN查询经常会对性能造成负面影响,因为它没有利用L2缓存转载 2023-03-02 06:48:56 · 211 阅读 · 0 评论 -
读Java性能权威指南(第2版)笔记07_即时编译器上
如果C1编译器队列已满,那么计划在级别3上编译的方法在等待编译的同时,可以进行级别4的编译。C1编译器得到代码是如何使用的信息之后,会利用这些信息进行优化,然后才开始编译。如果没有额外的CPU周期可用,你能做的就是尽量缩减应用程序的大小。如果C2编译器队列已满,那么队列中的方法会被取出,在级别2上编译。C1编译器有3个级别,所有总共有5个编译级别。不重要的方法可以从级别2或者级别3开始编译。即时编译器是Java虚拟机的核心。编译器不得不“撤销”之前的编译。原生方法封装时发生的编译。在阻塞模式下发生的编译。转载 2023-03-03 07:15:00 · 157 阅读 · 0 评论 -
读Java性能权威指南(第2版)笔记08_即时编译器中
一旦代码执行到一定次数,就达到了它的编译阈值,编译器就会认为它有足够的信息来编译代码。编译器使用的计数器会随着方法和循环的执行增加计数,但是它们也会随着时间的推移而减少。在Docker容器中运行旧版本的JDK 8会导致自动优化出问题。可用的CPU有限,较少的线程竞争系统资源对性能有益。在当前的JVM中,优化阈值的意义不大。C1编译器和C2编译器有不同的队列。调用次数更多的方法有更高的优先级。需要编译的代码会放在编译队列中。编译器能够进行的最复杂的优化。转载 2023-03-06 07:15:00 · 215 阅读 · 0 评论 -
读Java性能权威指南(第2版)笔记09_即时编译器下
GraalVM优化代码时并没有C2编译器那么激进,所以对于运行得足够久的应用程序,传统的JVM最终会胜出。如果不让预编译的方法被C2编译器编译,那么服务器预热后的性能就会比它最终可能达到的性能差。给定足够长的预热期,禁用分层编译时的执行情况和开启时应该是差不多的。生成的二进制文件启动速度很快,特别是相较于在JVM中运行的程序。对于很小的、快速运行的程序没有帮助,甚至会阻碍它们的运行。原生程序的内存占用在开始时比传统JVM少得多。当在内存受限的环境中运行时有理由关闭它。对于比较大的程序有好处。转载 2023-03-07 07:15:00 · 370 阅读 · 0 评论 -
读Java性能权威指南(第2版)笔记10_原生内存
减小堆的最大值(或者设置GC优化参数,让堆永远不会完全占满)可以限制程序的内存占用。长期运行的JVM几乎总能受益于大页的使用,特别是当它有大堆时。请求巨页的程序会获得巨页,其他程序会获得常规的4 KB的页面。线程栈是相当大的,特别是对于64位的JVM来说。操作系统分配的页面比物理内存能容纳的页面多很多。-XX:-AutoShutdownNMT标志。没有程序可以获得巨页,即使是请求了巨页的程序。在可能的情况下,所有的程序都会获得巨页。提交的内存会随着堆的增加而相应增加。原生内存指代JVM的非堆内存。转载 2023-03-08 07:15:00 · 174 阅读 · 0 评论 -
读Java性能权威指南(第2版)笔记11_堆内存上
一般的经验法则是,寻找路径应该从集合对象(如HashMap)而不是从条目(如HashMap$Entry)开始,并且要寻找最大的集合。用于识别由于某种特定类型的对象创建得太多而导致的内存问题。对象的深大小和保留大小的区别在于其引用的对象是否是共享的。快速查看应用程序中对象数量的方法,不需要生成完整堆转储。使用更少的内存是提高垃圾回收器效率最好的办法。对象的浅大小(shallow size)保留大量堆空间的对象通常被称为堆的支配者。对象的深大小(deep size)最强大的跟踪内存使用的技术。转载 2023-03-09 07:15:00 · 146 阅读 · 0 评论 -
读Java性能权威指南(第2版)笔记12_堆内存中
对于使用线程安全对象的代码,延迟初始化时应该使用双重检查锁。只有在常用路径不会初始化变量时,才应该使用延迟初始化。不可变对象为标准化这种特殊的生命周期管理提供了可能性。如果减少GC是目标,大多数人可能更倾向于重新计算。即使实例变量是null,也会消耗对象类内的空间。最常见的Java对象是不可变的String对象。设为null来及早清理。转载 2023-03-10 07:15:00 · 211 阅读 · 0 评论 -
读Java性能权威指南(第2版)笔记13_堆内存下
当对象的数量不太多时,软引用的效果才会好,否则,还是要考虑使用更传统的、大小有界的对象池,并且以LRU缓存形式实现。被封装的这个对象被称为所引对象。使用了31 GB的堆并启用了压缩的oop的程序,通常比使用了33 GB堆的程序快。一旦更多的内存被添加到堆中以弥补未压缩的引用所使用的空间,GC周期的数量就会减少。不确定引用会消耗自身的内存,而且会长时间持有其他对象的内存,应尽量少用。限流对池性能的影响是有利的,池允许对稀缺资源的访问进行限流。普通类的大型对象池带来的性能问题肯定会比解决的问题还多。转载 2023-03-11 07:15:00 · 228 阅读 · 0 评论 -
读Java性能权威指南(第2版)笔记14_垃圾回收A
另一组执行GC,当GC线程跟踪对象引用(用于回收对象)或者在内存中移动对象时,它们必须确保应用程序线程不使用这些对象。所有线程都停止运行的停顿被称为STW停顿(stop-the-world pause)单个请求会受停顿时间的影响,尤其是Full GC时较长时间的停顿。优化垃圾回收器比跟踪指针引起的bug要容易得多(且耗时更少)GC是查找不再使用的对象,然后回收这些对象相关内存的过程。对象可以在被需要时创建,不再使用时由JVM自动回收。低停顿(low-pause)回收器。无停顿(pauseless)回收器。转载 2023-03-12 07:15:00 · 176 阅读 · 0 评论 -
读Java性能权威指南(第2版)笔记15_垃圾回收B
即使任务不是CPU密集型的,如果它产生的Full GC相对较少或者老年代一般是满的,Throughput垃圾回收器也可能是更好的选择。当应用程序的运行时间是关键时,如果Throughput垃圾回收器的应用程序线程停顿时间比G1 GC少,那么它就更有优势。堆很小(比如100 MB)的应用程序,无论可用的核心数量是多少,使用Serial垃圾回收器可能都会有更好的表现。在CPU周期足够的情况下,即使Serial垃圾回收器是默认的选择,G1 GC一般也会表现得更好。在JDK 8中,要如何选择则取决于你的应用程序。转载 2023-03-13 07:15:00 · 143 阅读 · 0 评论 -
读Java性能权威指南(第2版)笔记16_垃圾回收C
如果JVM发现堆在初始大小时,GC的次数太多,它就会不断地增加堆大小,直到JVM执行的GC数量“适当”,或者直到堆大小达到最大值。除非应用程序需要比默认值更大的堆,否则优化时可以调整GC算法的性能目标而不是微调堆的大小。对于不需要堆很大的应用程序来说,根本不需要设置堆的大小,只需要设定GC算法的性能目标。优化分代大小的命令行标志,调整的都是新生代的大小,老年代自动得到剩余的所有空间。一个有效的经验是,调整堆的大小,让其在Full GC之后,仍然被占用30%随着堆的大小增加,停顿的持续时间也会增加。转载 2023-03-14 07:15:00 · 178 阅读 · 0 评论 -
读Java性能权威指南(第2版)笔记17_垃圾回收D
默认情况下,JVM将在机器的每个CPU上都运行一个线程,最多同时运行8个,达到这个阈值后,JVM每1.6个CPU会再增加一个新线程。定义并丢弃大量类的应用程序,在元空间被填满且旧的类被删除时,偶尔会发生Full GC。如果在应用程序的启动过程中(它在加载类)有大量的Full GC,往往是因为永久代或元空间正在调整大小。当多个JVM运行在同一台机器上时,基于公式计算出的线程数量会过高,实际情况中必须减少使用的线程数量。当JVM加载类时,它必须记录这些类的某些元数据,这些数据占据的一个单独的堆空间,即元空间。转载 2023-03-15 07:15:00 · 158 阅读 · 0 评论 -
读Java性能权威指南(第2版)笔记18_垃圾回收E
2.5.5.1. 设定你希望应用程序在GC上花费的时间(相对于应用程序线程应该运行的时间)2.5.3.4. 如果使用了一个非常小的值,那么应用程序最终会得到一个非常小的老年代。3.11.1.2. 避免这些失败的最简单的方法(在可能的情况下)是增加堆的大小。2.4.2.2.1. 增加堆的大小可以减少Full GC停顿的次数。3.8.2.2. 并发模式失败随着堆的增长而影响更大的原因之一。3.11.4.5. 此处的占用率是基于老年代的,而不是整个堆。2.4.2.1.1. 更大的堆会消耗机器上更多的内存。转载 2023-03-16 07:15:00 · 197 阅读 · 0 评论 -
读Java性能权威指南(第2版)笔记19_垃圾回收F
在它还没有清理出足够的空间之前,有太多的对象从新生代晋升,以至于老年代的空间还是用完了。1.5.4.5.2. 在JDK 8中,当它需要进行回收时,G1 GC会在主堆上执行Full GC(紧跟着新生代回收)2.11.3.2. 增加MaxGCPauseMillis标志的值,可以在每次Mixed GC期间回收更多的老年代区域。1.5.3.4. 将执行多次,持续到(几乎)所有标记的区域都完成回收,恢复常规的Young GC周期。1.5.3.2. 执行正常的新生代回收时,也会回收后台扫描时标记的一些区域。转载 2023-03-17 07:15:00 · 199 阅读 · 0 评论 -
读Java性能权威指南(第2版)笔记20_垃圾回收G
1.4.1. Survivor空间非常小,当目标Survivor空间在新生代回收过程中被填满时,Eden空间中剩余的任何活跃对象都会被直接移入老年代。1.4.2. 对于停留在Survivor空间中的对象,其经历的GC周期数量有限制,超过这个限制的对象会被直接移入老年代。1.1.1. 刚刚被创建并且还在使用中,所以不能被回收,但它们的寿命并没有长到足以进入老年代。1.1.2. 仍在新生代中的对象有额外的机会被回收,而不是晋升到(并填满)老年代。2.9.2. -XX:-ResizeTLAB标志。转载 2023-03-18 07:15:00 · 213 阅读 · 0 评论 -
读Java性能权威指南(第2版)笔记21_垃圾回收H
2.11.3. 小于-XX:OldSize=N的值(默认是4 MB)与-XX:NewSize=N的值(默认是1 MB)之和,那么新生代和老年代的大小之和将作为堆的初始大小。2.10.3. 只有192 MB内存的机器上,JVM会将堆的最大值限制为96 MB或者更少。3.4.1. 针对运行单个JVM的、非常大的机器,它会尝试给堆的参数设置合理的值。3.5.2. 每个线程都有这样的区域,在GC 清理分代的过程中会用到。2.9.1. 设置JVM应该使用的默认最大值。2.8.1. 堆大小的默认最大值。转载 2023-03-19 07:15:00 · 125 阅读 · 0 评论 -
读Java性能权威指南(第2版)笔记22_ 操作系统工具和Java监控工具
2.8.3. 如果运行队列在相当长的时间内过长,那就说明机器已经过载,需要想办法减少机器当前的工作量。2.6.2.2. 不要仅仅因为有空闲的CPU可用,就认为应该增加线程池的大小以完成更多的工作。5.1.4. product表示该标志的默认设置在所有平台是统一的。4.5.3. 显示了命令行设置的标志和JVM直接设置的一些标志。5.1.3. 没有冒号,表示当前的值是这个版本JVM的默认值。2.8.2.2. 处理器队列长度不包含正在运行的线程的数量。2.8.1.2. 运行队列表示的是机器上所有的进程信息。转载 2023-03-20 07:15:00 · 265 阅读 · 0 评论 -
读Java性能权威指南(第2版)笔记23_ 性能分析工具
1.5.1. 通过socket或者被称为JVM工具接口(JVM Tool Interface,JVMTI)的原生Java接口进行的。2.4.5. 正在执行Java本地接口(Java Native Interface,JNI)代码(执行GC锁定函数除外)3.4.1. 采样分析器将性能问题指向某个包或某段代码,然后探查分析器在需要时深入研究此代码。2.5.1. JVM可以在任何时间点提供栈信息,而无须等待线程到达(同步)安全点。2.5.4. 以异步方式收集栈信息的采样分析器引入的测量失真更小。转载 2023-03-21 07:15:00 · 143 阅读 · 0 评论 -
读Java性能权威指南(第2版)笔记24_ Java飞行记录器JFR
7.5.2. 每个读写调用的时长,导致读写耗费大量时间的具体文件和套接字。7.4.1. 堆分配的数量和线程本地分配缓冲区(TLAB)的大小。1.1.1. 最初是BEA公司的JRockit JVM的功能。7.3.2. 抛出的异常和错误的数量,以及异常创建时的栈轨迹。7.6.2. 阻塞具体线程的具体管程,以及被阻塞的时长。7.4.2. 堆中分配的具体对象和它们分配时的栈轨迹。7.2.3. 哪些线程被阻塞在锁上(以及具体的锁)7.8.2. JFR只是统一了几个来源的信息。7.1.1. 加载和卸载的类的数量。转载 2023-03-22 07:15:00 · 402 阅读 · 0 评论 -
读Java性能权威指南(第2版)笔记25_性能测试方法上
1.3.5.1. 对于不那么频繁的操作,修复微基准测试发现的纳秒级别的回归问题就会浪费时间,将这些时间用于优化其他操作必然更有益。2.3.7.3. 如果你只能测量一个数字,那么最好选择基于百分位响应时间的测试,因为减小这个数字将惠及大多数用户。1.4.1. 要测量一个应用程序的性能,最好的测量对象就是应用程序本身,外加它使用的任何外部资源。1.5.6. 用介基准测试进行自动化测试也是很好的方法,特别是在模块级别的测试中。1.5.5. 介基准测试的性能特点比微基准测试的更接近实际应用程序。转载 2023-03-23 06:30:00 · 186 阅读 · 0 评论 -
读Java性能权威指南(第2版)笔记26_性能测试方法下
1.5. 正确判断两个测试的结果是否有差异需要进行一定程度的统计分析,以确保感知到的差异不是随机波动造成的。2.5.1. 很多重要的调优标志会基于JVM运行的底层硬件系统,计算出它们的默认值。2.5.3. 软件缓存和更重要的硬件缓存,在不同的系统和不同的负载下的表现也不同。1.4. 结果的变化越大,越难判断平均值的差异是由于真正的性能问题还是随机变化。3.9. 对于更稳定的测试,降低这些参数的值一般可以缩短运行测试所需的时间。2.2.2. 代码的性能特征会随着代码的变化而变化。转载 2023-03-24 06:30:00 · 140 阅读 · 0 评论 -
读Java性能权威指南(第2版)笔记27_线程和同步性能上
2.9. 在批处理应用程序中,无论是在创建线程池时分配线程(将最小线程数和最大线程数设置为相同的值,就会出现这种情况),还是按需分配线程,都不重要,因为执行应用程序所需的时间是一样的。3.5. 父任务必须等待其子任务完成,而线程池执行器中的线程不能向队列中添加另一个任务并等待任务完成,一旦其线程处于等待状态,它就不能用来执行任何子任务了。4.6.1. 意味着池中的每个线程都有一个自己所派生任务的队列。线程会优先处理自己队列中的任务,如果自己的队列是空的,那么它们会从其他线程的队列中窃取任务。转载 2023-03-25 06:30:00 · 187 阅读 · 0 评论 -
读Java性能权威指南(第2版)笔记28_线程和同步性能中
2.4.1. 不同于C++和C这样的语言,它对关于同步的内存语义有严格的保证,并且该保证适用于基于CAS的保护、传统的同步,以及volatile关键字。所以这种情况是最常遇到的。2.5. 同步的内存语义、基于CAS的结构,以及volatile关键字会对性能产生负面影响,特别是在有很多寄存器的大型机器上。3.6. 如果对资源的访问存在轻度或者适度的竞争,基于CAS的保护会比传统的同步更快(通常会快得多)4.4. 伪共享造成的最严重的损失,基本上每个写操作都会使所有其他缓存行失效,而且性能是串行的。转载 2023-03-26 06:30:00 · 149 阅读 · 0 评论 -
读Java性能权威指南(第2版)笔记29_线程和同步性能下
4.3. 在Windows上,Java优先级较高的线程往往比优先级较低的线程运行得更多,但即使是低优先级的线程也会获得相当多的CPU时间。4.1. 每个Java线程都有一个由开发人员定义的优先级,这是对操作系统的一种提示,用来说明程序认为特定线程有多重要。2.4. 在Unix风格的系统上,用户创建的进程(他们正在运行的所有程序)已经达到了此次登录配置的最大进程数。2.1. 在32位的JVM中,进程使用的内存达到了4 GB(或者小于4 GB,取决于操作系统)的最大大小。转载 2023-03-27 06:30:00 · 174 阅读 · 0 评论 -
读Java性能权威指南(第2版)笔记30_Java服务器
3.4. 像所有受限于CPU的情况一样,线程的数量没有必要比运行服务器的机器或容器的虚拟CPU数量多,因为永远没有办法运行那么多的线程。3.2. 选择器通知有客户端I/O待处理之后,另一个包含工作线程的线程池会处理实际的请求和响应。4.5. 与使用传统I/O构建的客户端相比,使用NIO构建的异步HTTP客户端需要的线程更少。4.4.3.2. 请求的连接超过了配置的数量,它们会在需要的时候被创建,在完成任务后被销毁。3.6.3. 在排队等待响应之前,看看异步线程池的状态,如果系统太忙,就拒绝请求。转载 2023-03-28 06:30:00 · 299 阅读 · 0 评论
分享