Java性能权威指南-总结14

news2024/12/28 17:54:01

Java性能权威指南-总结14

  • 堆内存最佳实践
    • 对象生命周期管理
      • 对象重用

堆内存最佳实践

对象生命周期管理

在很大程度上,Java会尽量减轻开发者投入到对象生命周期管理上的精力:开发者在需要的时候创建对象,当不再需要这些对象时,它们会走出作用域,并由垃圾收集器释放。

有些情况下,正常的生命周期并不是最优的。有些对象创建的成本很高,而管理这些对象的生命周期可以改进应用的效率,即便以让垃圾收集器多做些工作为代价。

对象重用

对象重用通常有两种实现方式:对象池和线程局部变量。这两种技术都会影响GC的效率,特别是对象池。

对象池技术存在的问题显而易见:被重用的对象会在堆中停留很长时间。如果有大量对象存在于堆中,那用来创建新对象的空间就少了,因为GC操作会更为频繁。

**对象创建时是分配在Eden区的。在最终提升到老年代之前,会在Survivor区反复经历一些Young GC周期。**每当处理到最近创建或者新创建的池化对象时,GC算法必须执行一些工作,去复制这个对象,并调整指向它的引用,直到该对象最终进入老年代。

一旦对象被提升到老年代,可能引发的性能问题甚至会更多。执行一次Full GC所花的时间与老年代中仍然存活的对象数量成正比。 存活对象的数量甚至比堆的大小更重要;处理一个3GB大小但存活对象很少的老年代,与处理一个1GB大小但存活对象占75%的老年代相比,速度要快一些。

使用某个并发收集器避免Full GC并不能使情况有所好转,这是因为,并发收集器的标记堆内存最佳实践阶段所花的时间也依赖于仍存活数据的数量。特别是对CMS而言,池中的对象很可能会在不同的时间被提升,这会增大因碎片而导致的并发故障的机会。总的来说,对象在堆中存留的时间越长,GC的效率越差。因此,大部分情况对象重用并不好。

JDK提供了一些常见的对象池:线程池和软引用。 软引用本质上是一大池可重用对象。同时Java EE依赖对象池来连接数据库和其他资源,而且EJB(Enterprise Java Beans)的整个生命周期都是围绕对象池的概念构建的。

线程局部变量的情况类似;JDK中到处是使用线程局部变量的类,以避免重新分配特定种类的对象。之所以要重用对象,原因是很多对象初始化的成本很高,与增加的GC时间这一点相权衡,重用更为高效。对于像JDBC连接池这样的东西,肯定如此:创建网络连接,以及可能还要进行的登录和建立数据库会话,成本非常高。这种情况下,对象池有很大的性能优势。线程也可以池化,以节省创建线程的时间;随机数生成器是作为线程局部变量提供的,以节省生成随机数的时间;诸如此类。

这些例子有一个共同的特性,即初始化对象需要的时间较长。 在Java中,对象分配非常快,成本也不高。对象初始化的性能取决于对象本身。应该只考虑重用初始化成本非常高的对象,而且是只有当初始化这些对象的代价在程序中是主导性操作之一时。

这些例子还有一个共性,那就是所共享对象的数目往往很小,以便最小化对GC的影响:即它们的数量较小,还不足以降低GC周期。 池中有少量对象,对GC效率不会影响太大;如果堆中满是池化对象,就会严重影响GC了。

下面是JDK和Java EE中重用对象的一些例子,以及重用的原因:
线程池
线程初始化的成本很高。
JDBC池
数据库连接初始化的成本很高。
EJB池
EJB初始化的成本很高。
大数组
Java要求,一个数组在分配的时候,其中的每个元素都必须初始化为某个默认值(null0或者false,根据具体情况而定)。对于很大的数组,这是非常耗时的。
原生NIO缓冲区
不管缓冲区多大,分配一个直接的java.nio.Buffer(即调用allocateDirect()方法返回的缓冲区),这个操作都非常昂贵。最好是创建一个很大的缓冲区,然后通过按需切割的方式来管理,以便将其重用于以后的操作。
安全相关类
MessageDigest、Signature以及其他安全算法的实例,初始化的成本都很高。基于Apache的XML代码就是使用线程局部变量保存这些实例的。
字符串编解码器对象
JDK中的很多类都会创建和重用这些对象。在大多数情况下,这些还是软引用。
StringBuilder协助者
BigDecimal类在计算中间结果时会重用一个StringBuilder对象。
随机数生成器
Random类和(特别是)SecureRandom类,生成它们的实例的代价是很高的。
从DNS查询到的名字
网络查询代价很高。
ZIP编解码器
有一种有趣的变化,初始化的开销不是特别高,但是释放的成本很高,因为这些对象要依赖对象终结操作(finalization)来确保释放掉所用的原生内存。

此处讨论的对象池和线程局部变量两种方式,在性能上有些差别。下面详细看一下。

  1. 对象池

对象池不受人喜欢,原因有多个方面,只有部分原因和性能有关。线程池的大小可能很难正确地设置,它们将对象管理的负担又抛给程序员了:程序员不能简单地将对象丢出作用域,而必须记得将其返还到对象池中。不过这里的焦点是对象池的性能,它受如下几个因素的影响:
GC影响
保存大量对象会降低GC的效率(有时非常显著)。同步对象池必然是同步的,如果对象要频繁地移除和替换,对象池上可能会存在大量竞争。其结果是,访问对象池可能比初始化新对象还慢。
限流(Throttling)
对象池对性能也有正面的影响:对于对稀缺资源的访问,线程池可以起到限流作用。如果想增加的负载超出系统的处理能力,性能将下降。这是线程池之所以很重要的一个原因。如果有太多线程同时运行,CPU将不堪重负,而且性能会下降。

这一原则也适用于远程系统的访问,而且在JDBC连接中会经常见到。如果JDBC连接数超出数据库的处理能力,数据库的性能就会下降。在这些情况下,通过确定池的上限来限制资源数(如JDBC连接数)更好,即便这意味着应用中的线程必须等待一个空闲资源。

  1. 线程局部变量

在通过将对象保存为线程局部变量这种技术实现对象重用时,有不同的性能权衡,如下所列:
生命周期管理
线程局部变量要比在池中管理对象更容易,成本更低。这两种技术都邀请开发者去获取初始对象:或者是从对象池中检出,或者是在线程局部对象上调用get()方法。但是对象池还要求开发者在使用完毕后归还对象(否则其他人就不能使用了);线程局部对象在线程内总是可用的,不需要显式地归还。
基数性(Cardinality)
线程局部变量通常会伴生线程数与保存的可重用对象数之间的一一对应关系。不过并非严格如此。线程的变量副本,直到该线程第一次访问它时,才会创建,因此保存的对象数有可能小于线程数。但是保存的对象数不可能会超过线程数,大部分时间两者是相同的。

另一方面,对象池的大小则有些随意。如果一个Servlet有时需要一个JDBC连接,有时需要两个,则JDBC池的大小可以相应设定(比如说,对于8个线程,设定12个连接)。线程局部变量做不到这一点,也不能减少对资源的访问(除非线程数本身可以减少)。
同步
线程局部变量不需要同步,因为它们只能用于一个线程之内;而且线程局部的get()方法相当快。(情况并非一直如此,在早期的Java版本中,获得一个线程局部变量的开销很大。如果过去因为差劲的性能而远离了线程局部变量,在当前的Java版本中,可以重新考虑一下。)

同步还带来了一个有趣的问题,因为线程局部对象的性能优势通常会用节省了同步的代价来表达(而不说这是重用对象的好处)。比如,Java 7引入了一个ThreadLocalRandom类;这个类(而不是一个Random实例)也用到了示例股票应用中。此外,本书中的很多例子在Random对象的next()方法上都会遇到一个同步瓶颈。使用线程局部对象是避免同步瓶颈的好方法,因为只有一个线程能使用这个对象。

然而,只要让这个例子每次需要时,就简单地创建一个新的Random实例,同步问题也能轻松解决。不过,这样解决同步问题对整体性能没什么帮助:初始化一个Random对象的开销非常大,而且持续创建这个类的实例,与在多个线程间共享一个类实例的同步瓶颈相比,性能可能更差。

使用ThreadLocalRandom类性能会更好,如下表所示。这个例子使用了batching stock应用,对于每支股票,有创建新的Random实例和重用ThreadLocalRandom两种方案。
在这里插入图片描述
对于一般的对象重用,这里的经验是,在初始化对象需要很长时间时,不用畏惧探索用对象池或线程局部变量技术来重用那些创建开销高昂的对象。不过还是要找到一个平衡点:对于一般的类,较大的对象池所带来的性能问题很可能比解决的问题还要多。所以应该将这些技术应用于初始化成本高昂,以及重用对象的数目比较小时。
快速小结

  1. 对象重用通常是一种通用操作,并不鼓励使用它。但是这种技术可能适合初始化成本高昂,而且数量比较少的一组对象。
  2. 在使用对象池还是使用线程局部变量这两种技术之间,应该有所取舍。一般而言,建设线程和可重用对象直接存在一一对应关系,则线程局部变量更容易使用。

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

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

相关文章

C++11新特性之右值引用

目录 前文 一,什么是右值引用? 二,左值引用和右值引用比较 三,右值引用的应用场景以及作用 四, 右值引用左值的场景分析 五,完美转发 总结 前文 在C98标准后,C11标准的更新为C注入了新活力&…

chatgpt赋能python:Python如何生成100个随机整数

Python如何生成100个随机整数 在Python中,我们可以使用random库来生成随机整数。在本文中,我们将介绍如何使用Python生成100个随机整数。 什么是随机整数 随机整数是指在一定范围内,产生的整数是随机的且不重复的。这在数据分析、机器学习…

2. CSS的元素显示模式

了解元素的显示模式可以更好的让我们布局页面. 1.什么是元素的显示模式 2.元素显示模式的分类 3.元素显示模式的转换 2.1什么是元素显示模式 作用:网页的标签非常多,在不同地方会用到不同类型的标签,了解他们的特点可以更好的布局我们的网页。 元素显示…

chatgpt赋能python:如何在Python中创建模块:完整指南

如何在Python中创建模块:完整指南 如果你是一位Python开发者,你肯定需要用到模块。模块使得代码更容易组织和管理,并且可以复用许多代码片段, 提高代码的可重用性。在Python中,模块是一组相关函数,方法和变…

[论文笔记]End-to-end Sequence Labeling via Bi-directional LSTM-CNNs-CRF

引言 本文是论文End-to-end Sequence Labeling via Bi-directional LSTM-CNNs-CRF的阅读笔记。 本论文提出了一个受益于单词级(word)和字符级(character)表示的网络架构,通过组合双向LSTM,CNN和CRF。 简介 首先通过CNN编码一个单词的字符级信息到相应的字符表征。然后组合…

【C数据结构】动态顺序表_SeqList

目录 【1】数据结构概述 【1.1】什么是数据结构? 【1.2】数据结构分类 【1.3】数据结构术语 【2】数据结构特点 【2】动态顺序表 【2.1】动态顺序表定义数据结构和接口 【2.1】动态顺序表创建初始化 【2.2】动态顺序表初始化 【2.3】动态顺序表内存释放 【…

【Express.js】处理请求数据

处理请求数据 本节将具体介绍express后端处理请求源携带数据的一些方法和技巧 动态路径 很多时候我们需要处理一些类似但有操作差别或不同对象的业务,我们可以监听一段基本路径,将其中某一个段或者某几段路径作为变量,在接口中根据不同的路…

大学计算机专业实习心得报告13篇

大学计算机专业实习心得报告(篇1) 通过理论联系实际,巩固所学的知识,提高处理实际问题的能力,为顺利毕业进行做好充分的准备,并为自己能顺利与社会环境接轨做准备。通过这次实习,使我们进一步理…

chatgpt赋能python:如何用Python创建优秀的项目

如何用Python创建优秀的项目 Python是一种功能强大的编程语言,可用于创建各种不同类型的项目。本文将介绍如何使用Python创建优秀的项目,并包括一些有用的技巧和工具。在本文中,我们将着重讨论如何优化我们的Python项目以获得更好的SEO排名。…

Gitlab 服务器搭建

引言 GitLab 是一个用于仓库管理系统的开源项目,使用Git作为代码管理工具,并在此基础上搭建起来的Web服务。安装方法是参考GitLab在GitHub上的Wiki页面。Gitlab是被广泛使用的基于git的开源代码管理平台, 基于Ruby on Rails构建, 主要针对软件开发过程中…

C语言:求输入的两个数的最小公倍数

题目: 求输入的两个数的最小公倍数 思路一:普通方法 (思路简单,效率较低) 总体思路: (一). 输入两个数:a 和 b, 使用 三目表达式 把较大值 取出 &#xff…

[元带你学: eMMC协议详解 17] eMMC 安全方案 之 RPMB(Replay Protected Memory Block 重放保护内存块)

依JEDEC eMMC 5.1及经验辛苦整理,付费内容,禁止转载。 所在专栏 《元带你学: eMMC协议详解》 内容摘要 全文 6300 字, 主要内容有 目录 1 概念 2 容量大小 3 重放保护的原理 4 不同访问类型流程 4.1. 写认证密钥(write Au…

coder oss 真正私有化部署的云端开发环境,nas也可以装

先看效果: 主界面,显示了你有那些工作空间 某个工作空间,我这里集成了web版vscode,也可以使用本地的vscode和其他开发IDE 有独立的终端和集成webide 以后就可以一个ipad都可以写代码了; 下面是平台搭建过程&#xff0…

C语言入门基础知识(万字笔记)

一、前言部分 本篇文章,将会主要介绍c语言的基本数据类型、基本运算符、语句,三大结构、数组、指针、宏定义等内容 二、具体部分 1、基本数据类型 1、基本数据类型 在C语言中,承载一系列信息的数字或中字符都属于数据类型,计算…

产品设计.B端产品vsC端产品

一、用户群体 01、B端:一般是多角色群体、多维度,一般是3个维度,决策者(老板)、管理者(财务、业务部门负责人)和执行者(使用的用户)。 02、C端:群体相对单一…

K8s 中 port, targetPort, NodePort的区别

看1个例子: 我们用下面命令去创建1个pod2, 里面运行的是1个nginx kubectl create deployment pod2 --imagenginx当这个POD被创建后, 其实并不能被外部访问, 因为端口映射并没有完成. 我们用下面这个命令去创建1个svc &#xff…

msvcp140.dll是什么?怎么解决电脑提示msvcp140.dll丢失的问题?(分享解决方法)

msvcp140.dll是动态链接库文件,是一种不可执行的二进制程序文件,允许程序共享执行特殊任务所需要的代码和其他资源。程序可根据DLL文件中的指令打开、启用、查询、禁用和关闭驱动程序。 很多小伙伴在使用电脑软件的时候,有一些问题会搞不明白…

C语言之枚举联合

一、枚举 枚举顾名思义就是&#xff1a;列举 。 即把可能的取值一一列举出来 &#xff08;一&#xff09;枚举类型的定义 这里我们直接上代码&#xff1a; //枚举类型 #include <stdio.h>enum Sex//性别 {//枚举的可能取值-常量MALE 2,FEMALE 4,SECRET 8//以上为给…

LAMP架构及搭建LAMP+Discuz论坛

LAMP架构及搭建LAMPDiscuz论坛的流程 1、LAMP架构概述2、LAMP各组件的作用3、LAMP的安装顺序4、LAMP的数据流向5、编译安装Apache5.1 关闭防火墙和slinux&#xff0c;将安装Apache所需软件包传到/opt目录下并解压5.2 安装环境依赖包5.3 选择Apache软件模块5.4 编译和安装5.5 优…

使用 Sa-Token 实现 [记住我] 模式登录、七天免登录

一、需求分析 如图所示&#xff0c;一般网站的登录界面都会有一个 [记住我] 按钮&#xff0c;当你勾选它登录后&#xff0c;即使你关闭浏览器再次打开网站&#xff0c;也依然会处于登录状态&#xff0c;无须重复验证密码&#xff1a; 本文将详细介绍在 Sa-Token中&#xff0c;…