Java性能权威指南-总结19

news2024/11/20 20:42:02

Java性能权威指南-总结19

  • Java EE性能调优
    • JVM线程调优
      • 调节线程栈大小
      • 偏向锁
      • 自旋锁
      • 线程优先级
    • 小结
  • Java EE性能调优
    • Web容器的基本性能

Java EE性能调优

JVM线程调优

JVM的某些调优策略可以影响线程和同步的性能。

调节线程栈大小

当空间非常珍贵时,可以调节线程所用的内存。每个线程都有一个原生栈,操作系统用它来保存该线程的调用栈信息(比如,main()方法调用了calculate()方法,而calculate()方法又调用了add()方法,栈会把这些信息记录下来)。

不同的JVM版本,其线程栈的默认大小也有所差别,具体如下表所示。一般而言,如果在32位JVM上有128 KB的栈,在64位JVM上有256 KB的栈,很多应用实际就可以运行了。如果这个值设置得太小,潜在的缺点是,当某个线程的调用栈非常大时,会抛出StackoverflowError
几种JVM的默认栈大小:
在这里插入图片描述
在64位的JVM中,除非物理内存非常有限,并且较小的栈可以防止耗尽原生内存,否则没有理由设置这个值。 另一方面,在32位的JVM上,使用较小的栈(比如128 KB)往往是个不错的选择,因为这样可以在进程空间中释放部分内存,使得JVM的堆可以大一些。

耗尽原生内存
没有足够的原生内存来创建线程,也可能会抛出OutOfNemoryError。这意味着可能出现了以下3种情况之一。
1.在32位的JVM上,进程所占空间达到了4GB的最大值(或者小于4GB,取决于操作系统)。
2.系统实际已经耗尽了虚拟内存。
3.在Unix风格的系统上,用户创建的进程数已经达到配额限制。这方面单独的线程会被看作一个进程。

减少栈的大小可以克服前两个问题,但是对第三个问题没什么效果。遗憾的是,无法从JVM报错看出到底是哪种情况,只能在遇到错误时依次排查。
要改变线程的栈大小,可以使用-Xss=N标志(例如-Xss=256k)。

快速小结

  1. 在内存比较稀缺的机器上,可以减少线程栈大小。
  2. 在32位的JVM上,可以减少线程栈大小,以便在4GB进程空间限制的条件下,稍稍增加堆可以使用的内存。

偏向锁

当锁被争用时,JVM(和操作系统)可以选择如何分配锁。锁可以被公平地授予,每个线程以轮转调度方式(round-robin)获得锁。还有一种方案,即锁可以偏向于对它访问最为频繁的线程。

**偏向锁背后的理论依据是,如果一个线程最近用到了某个锁,那么线程下一次执行由同一把锁保护的代码所需的数据可能仍然保存在处理器的缓存中。如果给这个线程优先获得这把锁的权利,缓存命中率可能就会增加。**如果实现了这点,性能会有所改进。但是因为偏向锁也需要一些簿记信息,故有时性能可能会更糟。

特别是,使用了某个线程池的应用(包括大部分应用服务器),在偏向锁生效的情况下,性能会更糟糕。在那种编程模型下,不同的线程有同等机会访问争用的锁。对于这些类应用,使用-XX:-UseBiasedLocking选项禁用偏向锁,会稍稍改进性能。偏向锁默认是开启的。

自旋锁

在处理同步锁的竞争问题时,JVM有两种选择。对于想要获得锁而陷入阻塞的线程,可以让它进入忙循环,执行一些指令,然后再次检查这个锁。也可以把这个线程放入一个队列,在锁可用时通知它(使得CPU可供其他线程使用)。

如果多个线程竞争的锁的被持有时间较短,那忙循环(所谓的线程自旋)就比另一个方案快得多。如果被持有时间较长,则让第二个线程等待通知会更好,而且这样第三个线程也有机会使用CPU。 JVM会在这两种情况间寻求合理的平衡,自动调整将线程移交到待通知队列中之前的自旋时间。有些参数可以调整自旋时间,但大部分是实验性的,都有可能会发生变化,即使是极小的版本更新。

如果想影响JVM处理自旋锁的方式,唯一合理的方式就是让同步块尽可能短;当然不管什么情况,都是应该这么做的。这样可以限制与程序功能没有直接关系的自旋的量,也降低了线程进入通知队列的机会。

UseSpinning标志
之前的Java版本支持一个`-XX:+UseSpinning`标志,该标志可以开启或关闭自旋锁。在Java 7及更高版本中,这个标志已经没用了:自旋锁无法禁用。不过考虑到向后兼容,
Java 7到7u40这些版本的命令行参数仍然接受该标志,但是不执行任何操作。有点奇怪的是,这个标志的默认值会报告为false,即使自旋锁一直在发挥作用。

从Java7u40(以及Java8中)开始,Java不再支持该标志,使用这个标志会报错。

线程优先级

每个Java线程都有一个开发者定义的优先级,这是应用提供给操作系统的一个线索,用以说明特定线程在其眼中的重要程度。如果有不同线程处理不同任务,可能会认为,可以以让其他任务在优先级较低的线程上运行为代价,使用线程优先级来改进特定任务的性能。遗憾的是,实际不会这么有用。

操作系统会为机器上运行的每个线程计算一个“当前”(current)优先级。 当前优先级会考虑Java指派的优先级,但是还会考虑很多其他的因素,其中最重要的一个是:自线程上次运行到现在所持续的时间。这可以确保所有的线程都有机会在某个时间点运行。不管优先级高低,没有线程会一直处于“饥饿”状态,等待访问CPU。

这两个因素之间的平衡会随操作系统的不同而有所差异。在基于Unix的系统上,整体优先级的计算主要取决于线程上次运行到现在所持续的时间,Java层指定的优先级影响微乎其微。在Windows系统上,在Java层指定的优先级较高的线程,往往会比优先级较低的线程运行更久;但即便优先级较低,那些线程也会得到相对公平的执行时间。

不过,不管是哪种情况,都不能依赖线程的优先级来影响其性能。如果某些任务比其他任务更重要,就必须使用应用层逻辑来划分优先级。 在某种程度上,可以通过将任务指派给不同的线程池并修改那些池的大小来解决。

小结

理解线程如何运作,可以获得很大的性能优势。不过就线程的性能而言,其实没有太多可以调优的:可以修改的JVM标志相当少,而且那些标志的效果也很有限。

相反,较好的线程性能是这么来的:遵循管理线程数、限制同步带来的影响的一系列最佳实践原则。借助适当的剖析工具和锁分析工具,可以检查并修改应用,以避免线程和锁的问题给性能带来负面影响。

Java EE性能调优

Web容器的基本性能

Java EE应用服务器性能的关键是Web容器,它通过基本的servlet和JSP页面处理HTTP请求。有些基本的途径可以改善Web容器的性能,改进的具体方法因Java EE实现的不同而有所不同,但一些概念可以适用于所有服务器。

减少输出
减少服务器产生的结果输出可以加快Web页面返回到浏览器的速度。

减少空格
在servlet代码中调用PrintWriter时不要写入多余的空格,因为空格在网络上传输时同样需要时间(而且,相对于代码的处理,网络传输时间更为重要)。 应该用print()而不是println(),主要是为了避免在返回结果的HTML中写入制表符或空格。虽然这确实会使有些人查看Web页面源代码时看不清结构,但如果他们真对源代码感兴趣,总会使用XML或HTML编辑器。也可以让内部QA或者性能优化小组来处理空格。毫无疑问,结构化的页面源代码可以简化调试,但为了改善应用的响应时间,最后还得把它载入格式编辑器以去除多余的空格。绝大多数应用服务器都可以自动去除JSP页面中的空格。比如Tomcat(以及基于Tomcat的开源Java EE服务器)中的trimSpaces指令,可以将JSP页面每行的前后空格都去掉。所以开发和维护JSP页面时可以有适当的缩进,而不用担心会在网络上传输不必要的空格。

合并CSS和JavaScript资源
对于开发者来说,把CSS保存在独立的文件中是有意义的,也更容易维护。对于JavaScript来说也是如此。但使用这些资源时,传输一个大文件的效率比传输几个小文件要高。Java EE没有这方面的标准,而且绝大多数应用服务器也无法自动处理,不过有些开发工具可以帮助你合并这些资源。

压缩输出
从用户角度来看,执行Web请求的最长时间通常是服务器将HTML发回浏览器所需的时间。但由于客户端(模拟浏览器)到服务器的性能测试通常在快速局域网中进行,所以这个时间通常并不是最长的。虽然真实用户可能在“快速”广域网中,但仍然要比你实验室里的机器之间的LAN慢一个数量级。大多数应用服务器在将数据发回浏览器时都有压缩机制:HTML数据压缩发送给浏览器,内容类型(content type)为zip或gzip。这只有在初始请求指明浏览器支持压缩时才行得通。所有的现代浏览器都支持该特性。开启压缩要求服务器有更多的CPU周期,但通常数据量越小,网络传送的时间也越少,从而整体性能就会越高。然而与本节讨论的其他优化不同,它并不总能提高性能。后面的例子表明,在LAN开启压缩时,性能可能会下降。应用发送很小的页面时也会如此(尽管大多数应用服务器允许只有输出大于某个特定尺寸时才压缩)。

字符串是否应该预编码?
应用服务器在字符转换上要花费大量时间:从Java的String对象(以UTF-16格式保存)转换成客户端所需要的字节数组。许多这样的字符串总是相同的。
Web页面的HTML字符串并不会总随着数据发生变动(如果发生了,它们也仍然是从字符串常量集合中获取的)。

字符串是否预先编码取决于服务器:有些服务器会对此提供一个选项,有一些则是自动执行的。

在servlet中,这些字符串可以预编码,然后用ServletOutputStream的write()通过网络发送,不要用PrintWriter的print()。不过动态数据仍然要用print()才能正确编码。
(可以从header中找到目标编码,然后对字符串编码,但这种方法相对容易出错。)

应用服务器实现这些输出接口以及在其内部缓存这些数据的方式有很大差别。对一些服务器来说,混用servlet的输出流(output stream)和它的小伙伴print writer会导致频繁刷新网络缓存。

从性能优化角度看,频繁刷新缓存是非常昂贵的操作——比重新编码这些数据更昂责。与此类似,对一大块数据进行编码的代价通常不会比一小块数据高很多:最主要的代价是建立到编码器的调用。因此,对小段动态数据来说,频繁地编码及发送编码后的字节数组会拖慢应用:多次调用编码器所花费的时间,比一次调用编码所有的东西(包括静态数据)要长。
代码的预编码在某些情况下有一定作用,但要视情况而定。

与测试相比,这些优化措施实际运行中的性能会有很大差别。下表显示了可能会出现的结果。测试中所用股票历史servlet产生的输出比较长,获取的数据范围有10年。所产生的结果是未经压缩和未去除空格的HTML页面,大约为100 KB。为了将带宽的影响降至最低,测试只运行单个用户,思考时间为100毫秒,然后测量请求的平均响应时间。使用局域网时,测试通过100MB的交换机在本地网络上运行;使用宽带时,测试在家里的电缆上运行(平均每秒30 Mb的下载速度)。使用本地咖啡店中的公共WiFi连接的广域网时——网速是相当不可靠的(表格中展示了历时4个小时的平均样本)。
几种Web响应输出尺寸方面的优化在不同网络条件下的效果:
在这里插入图片描述

这张表强调了在应用的实际部署环境中进行测试的重要性。如果只在实验室环境中进行测试调优,那得到的一大半性能都是不太靠谱的。 虽然这个例子中的测试实际运行在远程应用服务器上(使用公有云服务),但硬件模拟器可以模拟出实验室环境,控制所有相关的机器。(云服务机器也比局域网机器快;它们之间的机器数量无法直接进行比较。)

快速小结

  1. 在Java EE应用所实际运行的网络基础设施上对它们进行测试。
  2. 外部网络相对内部网络来说仍然是慢的。限制应用所写的数据量会取得很好的性能。

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

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

相关文章

Day6——Web安全基础

网络安全学习笔记Day6 Web安全基础 一.Web简介什么是Web?什么是因特网?互联网,因特网,万维网的关系万维网构想的诞生http协议URL 二.Web发展史Web1.0Web2.01.0与2.0的区别Web1.0的安全漏洞Web2.0的安全漏洞 三.杂项门户网站静态页…

戴尔笔记本如何用U盘重装Win10系统?

戴尔笔记本如何用U盘重装Win10系统?很多使用戴尔笔记本的用户,都想知道如何用U盘来重装Win10系统,用户首先要确认自己的戴尔笔记本电脑能不能联网,然后再准备一个8G以上的U盘,最后根据小编分享的戴尔笔记本用U盘重装Wi…

Springboot Mybatis 不存在插入数据,存在则更新数据

前言 是不是经常看到代码, 查一下数据库,如果存在数据,就做更新语句调用; 如果不存在,就插入。 今天该篇介绍的 是使用 INSERT INTO ON DUPLICATE KEY UPDATE 来实现我们上述的场景, 不需要…

不能真“生成代码”的“低代码”平台,不可能获得程序员的认可

目录 前言 思考 解决问题 基本现状 发现亮点 前言 >前几天我和一个好友聊天的时候,他是这么评价低代码平台的:“想证明程序员都是傻X,又想让程序员买单!程序员本身心里就不爽... ” 那么,低代码发展势头迅猛的…

Live800:客服系统如何帮助企业优化服务流程

随着互联网的发展和社会进步,客服服务已经成为企业经营中不可或缺的一部分,然而,客服服务一直以来都备受诟病,用户对客服人员的不满情绪也随之而来。显然企业急需提升客户服务质量,这就离不开客服系统的帮助。 那么&am…

Linux系统中的信号

信号是由用户、系统或者进程发送给目标进程的信息,以通知目标进程某个状态的改变或系统异常。Linux信号可由如下条件产生: 对于前台进程,用户可以通过输入特殊的终端字符来给它发送信号。比如输入CtrlC通常会给进程发送一个中断信号&#xf…

人类语言和机器语言

人类语言和机器语言是两种不同的语言形式,二者之间有很多异同点。人类语言是人们日常交流所使用的语言,也是一种自然语言,人类语言是非常复杂和多样化的,包括文字、口语、手语等等,而机器语言则是非常简单和规范化的一…

Maven项目,本地jar包导入手动导入到Maven库中

当你的项目,由于网络或者环境这些问题,无法从maven中央仓库更新jar包到本地的时候,可以尝试下面方法,手动添加jar包到Maven仓库; 方法一(推荐): 1、需要先拿到你的jar包&#xff0…

Linux——3Linux用户和权限

目录 3.1 认识root用户 root用户(超级管理员) su 和 exit命令 sudo命令 3.2 用户、用户组 3.3 修改权限控制 - chmod 3.4 修改权限控制 - chown 3.1 认识root用户 root用户(超级管理员) 无论是Windows、MacOS、Linux均采…

8.10 TCP是如何实现可靠传输的

目录 TCP 最主要的特点 面向流的概念 Socket 有多种不同的意思 TCP是如何实现可靠传输的? A 如何知道 B 是否正确收到了 M1 呢? 确认丢失 确认迟到 连续 ARQ 协议 累计确认 TCP报文段的首部格式 TCP 最主要的特点 TCP 是面向连接的运输层协议&a…

基于Java理发店会员管理系统设计实现(源码+lw+部署文档+讲解等)

博主介绍:✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专…

深入探析CAN收发器NCV7342D10R2G各项参数

NCV7342D10R2G安森美深力科 CAN收发器是控制器局域网(CAN)协议控制器和物理总线之间的接口,可用于12V和24V系统。收发器向总线提供差分传输能力,向CAN控制器提供差分接收能力。由于接收器输入的共模电压范围很宽能够达到卓越的电磁…

charles unknown 问题和手机代理设置(iOS手机)

一、Charles下载 下载地址:https://www.charlesproxy.com/download/ 二、Charles配置代理 1.查看本机IP:help-->Local IP Address 2.查看或者设置访问端口:Proxy->Proxy Settings 3.设置不代理计算机的请求(推荐&#xff0…

【Java】Java核心 76:XML解析 Dom4j (下)

文章目录 **3** **使用xpath技术结合DOM4J技术读取xml文件(了解)**1.概念介绍2.XPath使用步骤3.XPath语法(了解)3.1全文搜索路径表达式方式 掌握 3 使用xpath技术结合DOM4J技术读取xml文件(了解) 1.概念介绍 问题:通过上面的案例我们发现有个小问题.就是获取标签的…

Python程序设计期末作品完整版|代码和程序设计文档

python程序设计作品,希望对您有帮助,希望您的一键三连! 程序设计报告 1.爬取数据的意义 富豪榜的出现,体现了人们思想的变化:由保守藏富向正向面对财富的转变;由保守向文明开放(–说明了大众媒体的进步与教育的普及等思想工具的极…

会网络爬虫能干什么?

网络爬虫是一种自动化程序,用于浏览互联网并从网页中获取数据。它可以执行以下任务: 数据采集:网络爬虫可以访问网站,并从中提取所需的数据,例如新闻文章、产品信息、用户评论等。这些数据可以用于各种目的&#xff0…

【数据结构导论】第 2 章:线性表

目录 一、线性表的基本概念 (1)线性表的基本概念 (2)线性表的逻辑结构特征 (3)线性表的基本运算 二、线性表的顺序存储 (1)线性表顺序存储的类型定义 (2&…

PHP 旅游网站系统mysql数据库web结构apache计算机软件工程网页wamp

一、源码特点 PHP 旅游网站系统 是一套完善的web设计系统,对理解php编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。开发环境为PHP APACHE,数据库为 mysql5.0,使用php语言开发。 代码…

Spark15-16

15. SparkOnYarn 15.1 Hadoop YARN回顾 15.1.1 YARN 的基本设计思想 将Hadoop 1.0中JobTracker拆分成两个独立的服务,一个全局的资源管理器ResourceManager(RM)和每个应用独有的ApplicationMaster(AM).其中RM负责整个系统的资源管理和分配,而AM负责单个的应用程序的管理 15.…

【面试题22】PHP通过Redis和MySQL实现商品秒杀功能

文章目录 一、前言二、系统架构三、技术栈四、系统设计4.1 商品设计4.2 用户设计4.3 抢单设计4.5 并发控制4.5 获取用户购买记录代码4.7 扣减商品库存代码4.8 获取商品锁代码4.9 添加订单记录代码 总结 一、前言 本文已收录于PHP全栈系列专栏:PHP面试专区。 计划将全…