system.gc 性能_使用这些先进的GC技术提高应用程序性能

system.gc 性能

应用程序性能是我们关注的重点,垃圾收集优化是取得小而有意义的进步的好地方
垃圾收集优化
自动化垃圾收集(与JIT HotSpot编译器一起)是JVM中最先进,最有价值的组件之一,但是许多开发人员和工程师对垃圾收集(GC),其工作方式以及如何影响应用程序性能的了解都很少。 。

首先,GC还能做什么? 垃圾收集是堆中对象的内存管理过程。 将对象分配给堆时,它们会经历几个收集阶段–通常相当快,因为​​堆中的大多数对象的寿命都很短。

垃圾收集事件包含三个阶段-标记,删除和复制/压缩。 在第一阶段,GC遍历堆,并将所有内容标记为活动(引用)对象,未引用对象或可用内存空间。 然后删除未引用的对象,并压缩剩余的对象。 在分代的垃圾收集中,对象“老化”并通过生活中的3个空间(伊甸园,幸存者空间和保有权(旧)空间)得到提升。 这种移动也作为压实阶段的一部分发生。

但是足够了,让我们进入有趣的部分!

了解Java中的垃圾回收(GC)

自动化GC的一大优点是,开发人员实际上不需要了解其工作原理。 不幸的是,这意味着许多开发人员不了解其工作原理。 了解垃圾收集和许多可用的GC,有点像了解Linux CLI命令。 从技术上讲,您并不需要使用它们,但是了解和使用它们会对您的生产率产生重大影响。

就像CLI命令一样,这里有绝对的基础知识。 ls命令查看父文件夹中的文件夹列表, mv将文件从一个位置移动到另一个位置,等等。在GC中,这些类型的命令等同于知道有多个GC可供选择,并且GC可能引起性能问题。 当然,还有很多东西要学习(关于使用Linux CLI和垃圾回收)。

了解Java的垃圾回收过程的目的不仅是免费(无聊)的对话入门者,其目的还在于学习如何针对特定环境有效地实现和维护具有最佳性能的正确GC。 知道垃圾回收会影响应用程序性能是基础,并且有许多先进的技术可以增强GC性能并减少其对应用程序可靠性的影响。

GC性能问题

1.内存泄漏–

通过了解堆结构以及如何执行垃圾回收,我们知道内存使用率逐渐增加,直到发生垃圾回收事件并且使用率回落为止。 被引用对象的堆利用率通常保持稳定,因此下降幅度应大致相同。

发生内存泄漏时,每个GC事件都会清除一小部分堆对象(尽管没有使用许多留在后面的对象),因此堆利用率将继续增加,直到堆内存已满,并且将抛出OutOfMemoryError异常。 原因是GC仅将未引用的对象标记为删除。 因此,即使不再使用引用的对象,也不会从堆中清除该对象。 有一些有用的编码技巧可以防止这种情况,稍后我们将介绍。

2.连续的“停止世界”活动–

在某些情况下,垃圾回收可以称为Stop the World事件,因为当垃圾回收发生时,JVM中的所有线程(因此,在其上运行的应用程序)都将停止以允许GC执行。 在健康的应用程序中,GC执行时间相对较短,并且不会对应用程序性能产生较大影响。

但是,在欠佳的情况下,“世界停止”事件可能会严重影响应用程序的性能和可靠性。 如果GC事件需要“停止世界”暂停并需要2秒钟的时间执行,则该应用程序的最终用户将遇到2秒的延迟,因为运行该应用程序的线程被停止以允许GC。

当发生内存泄漏时,连续的“停止世界”事件也是有问题的。 由于每次执行GC都会清除较少的堆内存空间,因此剩余内存填满的时间会更少。 当内存已满时,JVM会触发另一个GC事件。 最终,JVM将运行重复的Stop the World事件,从而引起严重的性能问题。

3. CPU使用率–

而这全都取决于CPU使用率。 连续GC /“停止世界”事件的主要症状是CPU使用率激增。 GC是一项计算量很大的操作,因此可能会花费比CPU功率更多的份额。 对于运行并发线程的GC,CPU使用率可能更高。 为您的应用程序选择合适的GC将对CPU使用率产生最大的影响,但是还有其他方法可以优化以提高该领域的性能。

从围绕垃圾收集的性能问题中我们可以了解到,尽管高级GC获得了(并且它们已经相当先进),但其致命弱点仍然保持不变。 冗余且不可预测的对象分配。 为了提高应用程序性能,仅选择正确的GC是不够的。 我们需要知道流程的工作方式,并且需要优化代码,以使我们的GC不会占用过多的资源或在应用程序中造成过多的暂停。

世代GC

在深入研究不同的Java GC及其对性能的影响之前,了解世代垃圾收集的基础很重要。 世代GC的基本概念基于这样的思想,即对堆中某个对象的引用存在的时间越长,将其标记为删除的可能性就越小。 通过使用具有象征意义的“年龄”标记对象,可以将它们分隔到不同的存储空间,以使GC进行标记的频率降低。

将对象分配给堆时,会将其放置在所谓的Eden空间中。 那是对象开始的地方,在大多数情况下,它们是标记为删除的地方。 在该阶段幸存的对象“庆祝生日”,并复制到Survivor空间。 此过程如下所示:

伊甸园和幸存者空间组成了年轻一代。 这是大部分操作发生的地方。 当(如果)年轻一代中的某个对象达到一定年龄时,该对象将被提升到终身(也称为旧)空间。 根据年龄划分对象内存的好处是GC可以在不同级别上运行。

次要GC是仅关注年轻一代的集合,实际上完全忽略了Tenured空间。 通常,年轻代中的大多数对象都标记为删除,并且不需要主或完全GC(包括旧代)来释放堆上的内存。 当然,必要时会触发“主要”或“完全” GC。

在此基础上优化GC操作的一个快速技巧是调整堆区域的大小,以最适合您的应用程序的需求。

收集器类型

有许多可用的GC可供选择,尽管G1成为Java 9中的默认GC ,但它最初旨在替代低暂停的CMS收集器,因此使用吞吐量收集器运行的应用程序可能更适合保留其当前收集器。 对于Java垃圾收集器,了解操作上的差异以及性能影响方面的差异仍然很重要。

吞吐量收集器

更适合需要针对高吞吐量进行优化的应用程序,并且可以交易更高的延迟来实现。

序列号–

串行收集器是最简单的收集器,也是您最不可能使用的收集器,因为它主要用于单线程环境(例如32位或Windows)和小型堆。 该收集器可以垂直扩展JVM中的内存使用量,但需要几个主要/完全GC才能释放未使用的堆资源。 这导致频繁的Stop the World暂停,从而使它在所有意图和目的上都失去了在面向用户的环境中使用的资格。

平行 -

顾名思义,此GC使用并行运行的多个线程来扫描并压缩堆。 尽管Parallel GC使用多个线程进行垃圾回收,但它仍在运行时暂停所有应用程序线程。 Parallel收集器最适合需要优化以实现最佳吞吐量并可以忍受更高延迟的应用程序。

低暂停时间收集器

大多数面向用户的应用程序需要低暂停GC,因此长时间或频繁的暂停不会影响用户体验。 这些GC都是为了优化响应能力(时间/事件)和强大的短期性能。

并发标记扫描(CMS)–

与并行收集器相似,并发标记扫描(CMS)收集器利用多个线程来标记和清除(删除)未引用的对象。 但是,此GC仅在以下两个特定实例中启动“停止世界”事件:

(1)初始化根的初始标记时(旧代对象可以从线程入口点或静态变量访问)或main()方法的任何引用,以及更多

(2)当应用程序在算法同时运行时更改了堆的状态时,迫使它返回并进行最后的修改以确保它标记了正确的对象

G1 –

垃圾第一收集器(通常称为G1)利用多个后台线程扫描通过堆将其划分为多个区域。 它的工作方式是先扫描那些包含最多垃圾对象的区域,然后为其命名(垃圾优先)。

这种策略减少了在后台线程完成对未使用对象的扫描之前耗尽堆的机会,在这种情况下,收集器将不得不停止应用程序。 G1收集器的另一个优点是它可以在移动过程中压缩堆,这是CMS收集器仅在完全Stop the World收集期间执行的操作。

改善GC性能

垃圾收集的频率和持续时间直接影响应用程序的性能,这意味着可以通过减少这些指标来优化GC流程。 有两种主要方法可以做到这一点。 首先,通过调整年轻人和老年人的堆大小 ,其次,以减少对象分配和提升的速度

在调整堆大小方面,它并不像人们期望的那么简单。 合理的结论是,增加堆大小将减少GC频率,同时增加持续时间,而减少堆大小将减少GC持续时间,同时增加频率。

不过,事实是,次要GC的持续时间不取决于堆的大小,而是取决于可以幸存的对象数量。 这意味着对于大多数创建寿命短的对象的应用程序,增加年轻代的大小实际上可以减少GC的持续时间频率。 但是,如果增加年轻代的大小会导致需要在幸存者空间中复制的对象显着增加,则GC暂停将花费更长的时间,从而导致延迟增加。

编写GC高效代码的3个技巧

提示1:预测收集容量–

所有标准Java集合以及大多数自定义和扩展的实现(例如Trove和Google的Guava)都使用基础数组(基于原始或对象的数组)。 由于数组一旦分配就大小不变,因此在许多情况下向集合中添加项目可能会导致丢弃旧的基础数组,而使用较大的新分配的数组。

即使未提供预期的集合大小,大多数集合的实现也会尝试优化此重新分配过程,并将其保持在摊销后的最小值。 但是,通过在构造时为集合提供预期的大小可以达到最佳效果。

提示2:直接处理流–

例如,在处理数据流(例如从文件读取的数据或通过网络下载的数据)时,通常会看到以下内容:

byte[] fileData = readFileToByteArray(new File("myfile.txt"));

然后可以将得到的字节数组解析为XML文档,JSON对象或Protocol Buffer消息,以列举一些常用的选项。

当处理大文件或大小无法预测的文件时,这显然不是一个好主意,因为在JVM无法实际分配整个文件大小的缓冲区的情况下,这会使我们面临OutOfMemoryErrors。

解决此问题的更好方法是使用适当的InputStream(在这种情况下为FileInputStream)并将其直接输入解析器,而无需先将整个内容读取到字节数组中。 所有主要的库都公开API以直接解析流,例如:

FileInputStream fis = new FileInputStream(fileName);
MyProtoBufMessage msg = MyProtoBufMessage.parseFrom(fis);

提示3:使用不可变对象–

不变性有很多优点。 很少受到关注的一个问题是它对垃圾收集的影响。

不变对象是指其对象(在我们的情况下尤其是非原始字段)在构造对象后便无法修改的对象。

不变性意味着不变容器引用的所有对象都是在容器构造完成之前创建的。 用GC的术语来说:容器至少与所保存的最小引用一样年轻。 这意味着在对年轻一代执行垃圾回收周期时,GC可以跳过位于老一代中的不可变对象,因为它可以确定它们不能引用正在收集的一代中的任何对象。

要扫描的对象越少,意味着要扫描的内存页面越少,而要扫描的内存页面就越少,意味着GC周期越短,这意味着GC暂停时间越短,总体吞吐量就越高。

有关更多技巧和详细示例,请查看这篇文章,其中涵盖了编写更多内存有效代码的深入策略。

***非常感谢OverOps研发团队的Amit Hurvitz对本文的热情和见解!

翻译自: https://www.javacodegeeks.com/2018/08/improve-application-performance-gc.html

system.gc 性能

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/333128.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux 命令之 who -- 打印当前登录用户/显示目前登入系统的用户信息。

文章目录命令介绍常用选项参考示例打印用户登录信息打印全面的信息打印系统登录进程显示登录系统的所有用户名称和总人数命令介绍 who 命令用来打印当前登录用户信息,包含了系统的启动时间 、 活动进程 、 使用者 ID、使用终端等信息,是系统管理员了解系…

SpringCloud全局过滤器自定义

一、实现步骤: 在gateway_service工程编写全局过滤器类GlobalFilter,Ordered编写业务逻辑代码访问接口测试,加token和不加token。 二、业务逻辑代码 package com.william.filters;import org.springframework.cloud.gateway.filter.GatewayFilterChain…

Linux 命令之 whoami -- 打印当前有效的用户名称

文章目录命令介绍参考示例命令介绍 whoami 命令用于打印当前有效的用户名称,相当于执行 id -un 命令。 参考示例 [roothtlwk0001host ~]# whoami root

java流写入数据库_使用Java流查询数据库

java流写入数据库在本文中,您将学习如何编写纯Java应用程序,这些应用程序能够使用现有数据库中的数据,而无需编写一行SQL(或类似的语言,如HQL),而无需花费数小时将所有内容放在一起。 准备好应用…

Linux 命令之 id -- 显示用户ID和组ID

文章目录命令介绍常用选项参考示例显示当前用户的用户id及所属用户组的信息显示用户所属群组的ID显示用户所属附加群组的ID显示指定用户信息命令介绍 id命令可以显示真实有效的用户ID(UID)和组ID(GID)。UID 是对一个用户的单一身份标识。组ID(GID)则对应…

SpringCloud局部过滤器自定义

一、实现步骤: 在gateway_service中编写MyParamGatewayFilterFactory类实现业务代码:循环请求参数中是否包含name,如果包含则输出参数值修改配置文件访问请求测试,带name参数 二、在gateway_service中编写MyParamGatewayFilterF…

enum.values_占用内存的Enum.values()方法

enum.values我是Java 枚举的忠实拥护者 。 似乎我们一直在等待获得它,但是当我们最终获得它( J2SE 5 )时,该枚举比C和C 提供的枚举要好得多,对我来说似乎“ 值得等待” 。 与Java enum一样好,它也不是没有问…

搭建配置中心微服务

一、实现步骤&#xff1a; 创建配置中心SpringBoot项目config_server配置坐标依赖启动类添加开启配置中心服务注解配置服务中心application.yml文件启动测试 二、创建配置中心SpringBoot项目config_server 配置坐标依赖 需要依赖父工程 <?xml version"1.0" en…

Linux命令之 users -- 显示当前登录的用户

文章目录命令介绍参考示例查看当前登录的所有用户命令介绍 users 命令用于显示当前登录系统的所有用户的用户列表。每个显示的用户名对应一个登录会话。如果一个用户有不止一个登录会话&#xff0c;那他的用户名将显示相同的次数。 参考示例 查看当前登录的所有用户 [rooth…

使用Spring Boot和H2可以正常工作的原型

我们确实在弹簧上使用了很多h2&#xff0c;特别是对于单元测试。 但是&#xff0c;我们可能希望有一个功能齐全的原型来显示数据&#xff0c;而不是进行单元测试。 H2是最理想的选择&#xff0c;它在spring上运行良好&#xff0c;与大多数数据库都具有良好的语法兼容性&#x…

服务去获取配置中心配置

目标&#xff1a;改造user_service工程&#xff0c;配置文件不再由微服务项目提供&#xff0c;而是从配置中心获取。 实现步骤&#xff1a; 添加配置中心客户端启动依赖修改服务提供者的配置文件启动服务测试效果 一、添加依赖 <!--spring cloud 配置中心--> <depe…

Linux查看用户信息/查看所有用户信息的命令

文章目录通过文件 /etc/passwd 来查看所有用户信息通过文件 /etc/shadow 查看所有用户信息使用 getent 命令查看所有用户信息使用 compgen 命令查看所有的用户信息相关文件/etc/passwd/etc/passwd 文件内容格式说明/etc/shadow/etc/group/etc/group 文件内容格式说明/etc/gshad…

graalvm_GraalVM上的Picocli:极快的命令行应用程序

graalvmGraalVM GraalVM允许您提前将程序编译为本地可执行文件。 与Java VM相比&#xff0c;生成的程序具有更快的启动时间和更低的运行时内存开销。 这对于通常寿命很短的命令行实用程序尤其有用。 GraalVM对Java反射的支持有限&#xff0c;它需要提前知道反射访问的程序元素…

Linux 命令之 getent -- 查看记录

文章目录命令介绍常用选项参考示例查看文件 /etc/protocols 中的所有记录查看指定用户组是否存在&#xff0c;若不存在则创建指定的用户组根据主机名称&#xff0c;查看对应的IP地址根据域名查找对应的IP根据用户名查找对应的UID获取当前登陆用户的信息根据UID查找用户名查找那…

运行SpringBoot时:Type javax.xml.bind.JAXBContext not present

原因和简单介绍 我有一些代码使用JAXB API类&#xff0c;它们是作为Java 6/7/8中JDK的一部分提供的。当我使用Java 9运行相同的代码时&#xff0c;在运行时我得到错误&#xff0c;指示无法找到JAXB类。 自Java 6以来&#xff0c;JAXB类已作为JDK的一部分提供&#xff0c;为什么…

Linux 命令之 chfn -- 修改用户信息

文章目录命令简介常用选项参考示例改变用户 root 的 finger 信息命令简介 chfn 命令的英文全称是 change finger&#xff0c;即用来改变 finger 命令显示的信息。这些信息都存放在 /etc/passwd 文件里。若不指定任何选项&#xff0c;则chfn 命令会进入问答式界面。 常用选项 …

cassandra可视化_容器化Spring Data Cassandra应用程序

cassandra可视化我正在继续学习Docker的旅程。 在这一点上&#xff0c;我仍然保持简单。 这次&#xff0c;我将解决将Spring和Cassandra应用程序转换为使用容器而不是在主机上本地运行的问题。 更确切地说&#xff0c;使用Spring Data Cassandra整理应用程序。 我希望我前几天…

自定义Mybatis框架

一、开发环境的准备及统一 1、 Jdk环境&#xff1a;JDK 1.8 64bit 2、 Maven环境&#xff1a;MAVEN 3.3.9 二、创建Maven工程并引入坐标 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"…

Linux 命令之 userconf -- 设置用户账号

文章目录命令介绍常用选项参考示例新增用户账号新增群组删除用户账号删除群组命令介绍 userconf的命令全称是“user config”&#xff0c;该命令是用户账号设置程序。 userconf实际上为linuxconf的符号连接&#xff0c;提供图形界面的操作方式&#xff0c;供管理员建立与管理各…

javafx 动画没效果_通过JavaFX标注制作动画效果

javafx 动画没效果在本文中&#xff0c;您将学习如何使用JavaFX的动画API创建标注。 您可以在https://www.youtube.com/watch?vXTHbB0LRdT4的 YouTube网站上查看这些标注的演示示例。 什么是标注&#xff1f; 我敢肯定&#xff0c;您已经看过广告或科幻电影&#xff0c;它们使…