草庐IT

读Java性能权威指南(第2版)笔记13_堆内存下

躺柒 2023-03-28 原文

1. 对象重用

1.1. 原因

1.1.1. 许多对象的初始化成本很高,权衡了增加的GC时间之后,还是重用对象的效率更高

1.2. 只适用于初始化成本很高且数量较少的一组对象

1.2.1. 被重用的对象会在堆中停留很长时间。如果堆中有大量对象,创建新对象的空间就更少了,因此GC操作会更频繁。

1.3. 方式

1.3.1. 对象池

1.3.1.1. 线程池化可以节省创建线程的时间

1.3.1.2. 在池中有少量对象并不会对GC效率产生太大影响,但堆中充满池化对象时会大大减慢GC的速度

1.3.2. 线程局部变量

1.3.2.1. 随机数生成器作为线程局部变量,可以节省使用随机数种子创建生成器所需的时间

1.4. 特点

1.4.1. 初始化对象需要很长的时间

1.4.2. 共享的对象数量往往很少

1.4.2.1. 它们对GC操作的影响降到了最低,因为它们不足以减慢GC周期

1.5. 应用场景

1.5.1. 线程池

1.5.1.1. 线程初始化的成本很高

1.5.2. JDBC连接池

1.5.2.1. 数据库连接初始化的成本很高

1.5.3. 大数组

1.5.3.1. 每个元素都必须初始化为基于0的默认值(null、0或false,视情况而定)

1.5.4. 原生NIO缓冲区

1.5.4.1. 无论缓冲区有多大,分配一个直接的java.nio.Buffer(调用allocateDirect()方法返回的缓冲区)都是成本很高的操作

1.5.4.2. 最好是创建一个大的缓冲区,然后通过按需切片的方式来管理缓冲区,以便在将来的操作中返回它们重新使用

1.5.5. 与安全相关的类

1.5.5.1. MessageDigest、Signature以及其他安全算法的实例

1.5.6. 字符串编码器和解码器对象

1.5.7. StringBuilder帮助类

1.5.8. 随机数生成器

1.5.8.1. Random类和(特别是)SecureRandom类的实例

1.5.9. 从DNS查询中获得的名字

1.5.9.1. 网络查询的成本很高

1.5.10. ZIP编码器和解码器

1.5.10.1. 初始化成本并不是特别高,但是它们的释放成本很高

1.5.10.2. 依赖对象终结(finalization)来确保它们使用的原生内存也被释放了

2. 对象池

2.1. 大小可能很难设置正确

2.2. 不能直接让对象退出作用域,程序员必须将对象返还到池中

2.3. 持有大量对象会降低GC的效率(有时会大幅降低)

2.4. 必然需要同步,如果对象被频繁地删除和替换,对象池可能会存在大量竞争

2.5. 普通类的大型对象池带来的性能问题肯定会比解决的问题还多

2.6. 限流对池性能的影响是有利的,池允许对稀缺资源的访问进行限流

3. 线程局部变量

3.1. 在线程内总是可用的,不需要显式地归还

3.2. 不能对资源的访问进行限流

3.2.1. 除非线程数量本身可以起到限流的作用

3.3. 不需要同步

3.3.1. 只能在单个线程内使用

3.3.2. 使用ThreadLocalRandom类性能会更好

3.4. 如果线程和可重用对象之间有一一对应的关系,那么线程局部变量更容易使用

4. 不确定引用

4.1. indefinite reference

4.2. 表示任何特殊类型的引用

4.2.1. 软引用或弱引用

4.2.2. 实际上是一个对象实例

4.3. 更多地用于缓存耗时的计算或数据库查询的结果,而不是用于重用一个简单对象

4.4. 对垃圾回收器的影响

4.4.1. 会导致应用程序使用更多的内存

4.4.2. 不确定引用被垃圾回收器回收至少需要两个GC周期,这对垃圾回收器的影响更大

4.4.2.1. 在最坏的情况下,引用队列不会被立即清理,而是需要经过很多GC周期后才会释放一切对象

4.5. -XX:+PrintReferenceGC标志

4.5.1. 看到处理引用所花费的时间

4.5.2. 默认为false

4.6. 不确定引用会消耗自身的内存,而且会长时间持有其他对象的内存,应尽量少用

5. 引用

5.1. reference

5.2. 一个引用(或对象引用)可以是任何类型的引用

5.3. 强引用、弱引用和软引用等

6. 所引对象

6.1. referent

6.2. 将另一个引用(几乎总是强引用)嵌入到不确定引用类的实例中。被封装的这个对象被称为所引对象

7. 软引用

7.1. Soft Reference

7.2. 当相关对象在未来有很大概率被重用,而你想让垃圾回收器回收最近没有用到的对象时使用

7.2.1. 软引用可以长期持有对象,它会提供一个简单的、GC友好的LRU缓存

7.3. 本质上是一个大型的、最近最少使用的(LRU)对象池

7.4. 获得良好性能的关键是要确保它被及时清理

7.5. 清理时机

7.5.1. 所引对象必须没有被其他的强引用所引用

7.5.2. 软引用是指向所引对象的唯一引用,那么当软引用最近没有被访问时,所引对象就会在下个GC周期被释放

7.6. -XX:SoftRefLRUPolicyMSPerMB=N标志

7.6.1. 默认值是1000

7.7. 长期运行的应用程序也可以考虑增加SoftRefLRUPolicyMSPerMB的值的条件

7.7.1. 堆中有大量空闲空间可用

7.7.2. 软引用的访问频率不高

7.8. 不要使用过多的软引用,它们很容易填满整个堆

7.9. 当对象的数量不太多时,软引用的效果才会好,否则,还是要考虑使用更传统的、大小有界的对象池,并且以LRU缓存形式实现

8. 弱引用

8.1. weak reference

8.2. 在相关所引对象会被几个线程同时使用时使用

8.3. 当强引用被清理时,弱引用立即被清理

8.4. 垃圾回收器在每个GC周期都会回收只有弱引用的对象

8.5. 集合类常常是内存泄漏的源头

8.5.1. WeakHashMap和WeakIdentityMap

8.5.2. 基于不确定引用的集合可能很有用,但是应该谨慎使用

9. 终结器和最终引用

9.1. 不鼓励使用终结器,应该使用新的Cleaner类

9.2. Object类的finalize()方法

9.2.1. 糟糕的方法,你应该尽量避免使用

9.2.2. 在JDK 11中被废弃了

9.3. Cleaner(清理器)对象

9.3.1. 使用新的java.lang.ref.Cleaner类代替finalize()方法会容易很多

9.3.2. 在JDK 11中使用

9.3.3. 执行清理的对象不能包含指向需要被清理的对象的引用

9.3.3.1. 因为lambda太容易引用外部类了,不鼓励开发人员使用lambda,而是要使用类

9.4. 如果你必须使用终结器,请确保将对象访问的内存保持在最低限度

9.5. 使用另一种类型的不确定引用,而不是隐式地使用Finalizer引用

9.5.1. PhantomReference类(虚引用)

9.5.1.1. JDK 11使用

9.6. 终结器队列

9.6.1. 当所引对象符合GC条件时,用来处理Finalizer引用的引用队列

9.6.2. 命令来处理终结器队列

9.6.2.1. % jcmd process_id GC.run_finalization

9.6.2.2. % jmap -finalizerinfo process_id

10. 普通对象指针

10.1. ordinary object pointer,oop

10.2. -XX:+UseCompressedOops

10.2.1. 对于4 GB到32 GB的堆,应该使用

10.2.2. 只要堆的最大大小小于32GB,标志默认启用

10.3. 使用了31 GB的堆并启用了压缩的oop的程序,通常比使用了33 GB堆的程序快

10.4. 最好使用小于32 GB的堆,或者至少比32 GB大几个GB的堆

10.5. 一旦更多的内存被添加到堆中以弥补未压缩的引用所使用的空间,GC周期的数量就会减少

10.6. 规划至少38 GB的堆是一个好的开始

有关读Java性能权威指南(第2版)笔记13_堆内存下的更多相关文章

  1. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

  2. java - 从 JRuby 调用 Java 类的问题 - 2

    我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www

  3. java - 我的模型类或其他类中应该有逻辑吗 - 2

    我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我

  4. java - 什么相当于 ruby​​ 的 rack 或 python 的 Java wsgi? - 2

    什么是ruby​​的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht

  5. Observability:从零开始创建 Java 微服务并监控它 (二) - 2

    这篇文章是继上一篇文章“Observability:从零开始创建Java微服务并监控它(一)”的续篇。在上一篇文章中,我们讲述了如何创建一个Javaweb应用,并使用Filebeat来收集应用所生成的日志。在今天的文章中,我来详述如何收集应用的指标,使用APM来监控应用并监督web服务的在线情况。源码可以在地址 https://github.com/liu-xiao-guo/java_observability 进行下载。摄入指标指标被视为可以随时更改的时间点值。当前请求的数量可以改变任何毫秒。你可能有1000个请求的峰值,然后一切都回到一个请求。这也意味着这些指标可能不准确,你还想提取最小/

  6. 【Java 面试合集】HashMap中为什么引入红黑树,而不是AVL树呢 - 2

    HashMap中为什么引入红黑树,而不是AVL树呢1.概述开始学习这个知识点之前我们需要知道,在JDK1.8以及之前,针对HashMap有什么不同。JDK1.7的时候,HashMap的底层实现是数组+链表JDK1.8的时候,HashMap的底层实现是数组+链表+红黑树我们要思考一个问题,为什么要从链表转为红黑树呢。首先先让我们了解下链表有什么不好???2.链表上述的截图其实就是链表的结构,我们来看下链表的增删改查的时间复杂度增:因为链表不是线性结构,所以每次添加的时候,只需要移动一个节点,所以可以理解为复杂度是N(1)删:算法时间复杂度跟增保持一致查:既然是非线性结构,所以查询某一个节点的时候

  7. ruby - 安装libv8(3.11.8.13)出错,Bundler无法继续 - 2

    运行bundleinstall后出现此错误:Gem::Package::FormatError:nometadatafoundin/Users/jeanosorio/.rvm/gems/ruby-1.9.3-p286/cache/libv8-3.11.8.13-x86_64-darwin-12.gemAnerroroccurredwhileinstallinglibv8(3.11.8.13),andBundlercannotcontinue.Makesurethat`geminstalllibv8-v'3.11.8.13'`succeedsbeforebundling.我试试gemin

  8. LC滤波器设计学习笔记(一)滤波电路入门 - 2

    目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称

  9. 【Java入门】使用Java实现文件夹的遍历 - 2

    遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg

  10. java - 为什么 ruby​​ modulo 与 java/other lang 不同? - 2

    我基本上来自Java背景并且努力理解Ruby中的模运算。(5%3)(-5%3)(5%-3)(-5%-3)Java中的上述操作产生,2个-22个-2但在Ruby中,相同的表达式会产生21个-1-2.Ruby在逻辑上有多擅长这个?模块操作在Ruby中是如何实现的?如果将同一个操作定义为一个web服务,两个服务如何匹配逻辑。 最佳答案 在Java中,模运算的结果与被除数的符号相同。在Ruby中,它与除数的符号相同。remainder()在Ruby中与被除数的符号相同。您可能还想引用modulooperation.

随机推荐