Java性能权威指南-总结25

news2024/11/25 18:42:14

Java性能权威指南-总结25

  • 数据库性能的最佳实践
    • 随机数
    • Java原生接口
    • 字符串的性能

数据库性能的最佳实践

随机数

Java7提供了3个标准的随机数生成器类:java.util.Randomjava.util.concurrent.ThreadLocalRandom以及java.security.SecureRandom。这三个类在性能方面差距很大。

RandomThreadLocalRandom两个类的差别是,Random类的主要操作(nextGaussian())是同步的。任何要获取随机值的方法都会用到这个方法,所以不管如何使用该随机数生成器,都会存在锁竞争:如果两个线程同时使用同一随机数生成器,那一个线程要等待另一个先完成其操作。 之所以会使用ThreadLocalRandom,原因就在于此:每个线程都有自己的随机数生成器,Random类的同步就不是问题了。(因为创建对象成本很高,而ThreadLocalRandom类会重用对象,所以有很大的性能优势。)

SecureRandom类与上面介绍的两个类的区别是,所用的算法不同。Random类(以及继承它而来的ThreadLocalRandom)实现了一个典型的伪随机数算法。尽管那些算法非常复杂,但到底是确定性的。如果知道初始种子,很容易确定该引擎将生成的数字的精确序列。这意味着,黑客能够从特定的生成器看到数字序列,也就能够指出下一个数字是什么。尽管好的伪随机数生成器可以生成看上去真正随机的数字序列(甚至符合随机性的概率期望),但这仍然不是真正的随机。

而另一方面,SecureRandom类使用一个系统接口来获得随机数。数据生成方式与所用的操作系统有关,不过一般而言,这类源提供了基于真正随机事件(比如鼠标移动时)的数据。这就是所谓的基于熵的随机性,比依赖随机数的操作更安全。SSL熵是这类操作中最广为人知的例子:加密所用的随机数不可能通过基于熵的源来确定。(即便在算法中使用了SecureRandom随机数生成器,还是有其他方式可以攻破数据的加密算法。)

计算机生成的熵的数量是有限的,所以要从一个安全随机数生成器获得大量的随机数,需要很长时间。调用SecureRandom类的nextRandom()方法消耗的时间并不确定,跟系统中还有多少熵尚未使用有关。如果没有熵可用,这个调用看上去就挂起了,可能一次长达数秒,直到有可用的熵为止。所以对性能的计时非常困难,因为性能本身也是随机的。

对于会创建很多SSL连接,或者需要大量安全随机数的应用而言,这往往会成为问题;这样的应用要花很多时间去执行其操作。当在一个这样的应用上执行性能测试时,计时会有很多变数。除了运行大量示例测试,其实没什么办法处理此类变数。

必要时,可以使用Random类运行性能测试,即便在生产环境中使用的是SecureRandom类。如果性能测试是模块级的,这会很有意义:在同样的一段时间内,与产品系统相比,这些测试需要的随机数更多(比如需要更多SSL套接字)。但是,最终预期的负载必须用SecureRandom类来测试,以确定生产系统上的负载是否能够获得足够的随机数。

快速小结

  1. Java默认的Random类的初始化的成本很高,但是一旦初始化完毕,就可以重用。
  2. 在多线程代码中,应该首选ThreadLocalRandom类。
  3. SecureRandom类表现出的性能也是随意的和完全随机的。在对用到这个类的代码做性能测试时,一定要认真规划。

Java原生接口

如果想编写尽可能快的代码,要避免使用JNI

在现行的JVM版本上,编写得好的Java代码至少会与相应的C或C++代码跑得一样快。然而这里要说的是:如果某个应用已经是用Java编写的,那出于性能原因调用原生代码几乎总是一个坏主意。

JNI有时仍然非常有用。Java平台提供了不同操作系统的很多公共特性,但如果需要访问一个特殊的、特定于操作系统的函数,那JNI就派上用场了。 如果有现成的商用原生代码,那为什么还要构建自己的执行操作的库呢?在这种情况和其他一些情况下,问题就变成了如何编写最高效的JNI代码。
答案是尽可能避免从Java调用C。跨JNI边界(边界是描述跨语言调用的术语)成本非常高,这是因为,调用一个现有的C库首先需要一些胶水代码,需要花时间通过胶水代码创建新的、粗粒度的接口,一下子要多次进入C库。

反过来就未必如此了:从C代码调用回Java不会有很大的性能损失(与所用的参数有关)。比如,考虑下面的代码:

    public void main() {
        calculateError();
    }
    
    public void calculateError() {
        for (int i = 0; i < numberOfTrials; i++) {
            error += 50 - calc(numberofIterations);
        }
    }
    
    public double calc(int n) {
        double sun = θ;
        for (int i = 0; i < n; i++) {
            int r = random(100);//返回1至100之间的一个随机值
            sum += r;
        }
        return sun / n;
    }

这段(完全没有实际意义的)代码有两个主循环:内层循环多次调用生成随机数的代码,外层循环重复调用内层循环,看看所得的随机数与预期值(这里是50)的接近程度。通过JNI,可以用C实现calculateError()calc()random()这些方法中的任何一个或多个。下表展示了不同组合情况下的性能,其中numberofTrials为10000。
在这里插入图片描述

仅用JNI调用实现最内层方法,跨JNI边界的次数最多(nunberOfTrials * numberofloops, 1千万次)。将跨边界次数减少到numberofTrials(即10000)可以大幅减少开销,而将其减到0,性能会最好——至少从JNI角度看是这样,尽管纯Java实现和完全使用原生代码一样快。

如果所用的参数不是简单的基本类型,JNI代码性能会更糟。这一开销涉及两个方面。

第一,对于简单的引用,需要地址转换。这也是为什么在上面的例子中,从Java调用C比从C调用Java开销更大:从Java调用C,会隐式地把问题中的对象(this)传递给C函数,从C调用Java则无需传递任何对象。

第二,对于基于数组的数据,其中的操作在原生代码中会进行特殊处理。这包括String对象,因为字符串数据本质上是一个字符数组。要访问这类数组中的单个元素,必须调用一个特殊的方法,将该对象固定在内存中(对于String对象,要将其从Java的UTF-16编码转换成UTF-8)。当不再需要数组时,必须在JNI代码中显式地释放。当有数组被固定在内存中时,垃圾收集器就无法运行——所以JNI代码中代价最高的错误之一就是在长期运行的代码中固定了一个字符串或数组。这会阻碍垃圾收集器运行,实际上也阻塞了所有应用线程,直到JNI代码完成。对于会固定数组的临界区,尽可能缩短固定时间极为重要。

有时,后面这个目标会与减少跨JNI边界调用这个目标冲突。这种情况下,后一个目标更重要:即使这意味着要多次跨JNI边界,也要让固定数组和字符串的代码区尽可能短。

快速小结

  1. JNI并不能解决性能问题。Java代码几乎总是比调用原生代码跑得快。
  2. 当使用JNI时,应该限制从JavaC的调用次数;跨JNI边界的调用成本很高。
  3. 使用数组或字符串的JNI代码必须固定这些对象;为避免影响垃圾收集器,应该限制固定对象的时间。

字符串的性能

字符串对Java非常重要。

字符串保留
创建多个包含相同字符序列的字符串对象,这种情况很常见。没有必要在堆中为所有这些对象都分配空间;因为字符串是不可变的,所以重用现有的字符串往往更好。

字符串编码
Java的字符串采用的是UTF-16编码,而其他地方多是使用其他编码,所以将字符串编码到不同的字符集的操作很常见。对于Charset类的encode()decode()方法而言,如果一次只处理一个或几个字符,它们会非常慢;务必完整缓存一些数据,再进行处理。

网络编码
在编码静态字符串(来自JSP文件等地方)时,Java EE应用服务器往往会特殊处理;字符串连接是另一个可能会出现性能问题的地方。考虑这样一个简单的字符串连接操作:

String answer = integerPart + "." + mantissa;

这行代码实际上非常高效;javac编译器的语法糖会将其转换为如下代码:

String answer = new StringBuilder(integerPart).append(".").append(mantissa).tostring();

不过问题来了,如果这个字符串是逐步构造起来的:

String answer = integerPart;
answer += ".";
answer += mantissa;

那么这段代码就会被翻译为:

String answer = new StringBuilder(integerPart).tostring();
answer = new StringBuilder(answer).append(".").toString();
answer = new StringBuilder(answer).append(mantissa).toString();

所有那些临时的StringBuilder对象和中间的String对象都很低效。永远不要使用连接来构造字符串,除非能在逻辑意义上的一行代码内完成;也不要在循环内使用字符串连接,除非连接后的字符串不会用于下一次循环迭代。 对于其他情况,应该总是使用StringBuilder,以获得更好的性能。

快速小结

  1. 一行的字符串连接代码性能很不错。
  2. 对于多行的连接操作,一定要确保使用StringBuilder

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

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

相关文章

SpringBoot教学资料1-SpringBoot基础

SpringBoot简介 Spring Boot 优点 •可快速构建独立的Spring应用 •直接嵌入Tomcat(无需部署WAR文件) •提供依赖启动器简化构建配置 •极大程度的自动化配置Spring和第三方库 •提供生产就绪功能 •极少的代码生成和XML配置 •Spring Boot是基于Spring框架开发的全新框架&…

jenkins使用ftp工具,上传文件至服务器报错“Could not write file”

一、错误说明 使用ftp上传文件 ERROR: Exception when publishing, exception message [Could not write file. Server message: [553 Could not create file.]]11:12:45 FTP: Connecting from host [test-xxx-java-user-service-3-932ft-hsb69-t5wmf] 11:12:45 FTP: Conne…

『DotNetBrowser』.Net的浏览器嵌入组件,该选择DotNetBrowser 还是 CefSharp?

&#x1f4e3;读完这篇文章里你能收获到 全方位对比DotNetBrowser 和 CefSharp的优缺点 文章目录 一、引言二、引擎三、架构1. CefSharp架构2. DotNetBrowser架构 四、对比1. 稳定性和内存使用2. 应用程序域3. AnyCPU4. H.264, AAC5. 安全6. Visual Studio设计器7. 嵌入应用程…

通过DAPLink和STLink使用RTT输出日志

前提 阅读此文章的前提是已经移植好SEGGER RTT&#xff0c;如未移植请参考我的另一篇博客 《基于J-Link RTT Viewer输出日志(适用于JLink DAPLink STLink)》 由于SEGGER RTT 自带的 JLinkRTTViewer.exe 只支持自家的J-Link&#xff0c;所以使用DAPLink和STLink我们得另辟蹊径…

【设计模式】第二十一章:命令模式详解及应用案例

系列文章 【设计模式】七大设计原则 【设计模式】第一章&#xff1a;单例模式 【设计模式】第二章&#xff1a;工厂模式 【设计模式】第三章&#xff1a;建造者模式 【设计模式】第四章&#xff1a;原型模式 【设计模式】第五章&#xff1a;适配器模式 【设计模式】第六章&…

shiro系列vulhub所有漏洞复现CVE-2020-1957、CVE-2016-4437、CVE-2010-3863、shiro-721 代码执行

文章目录 Apache Shiro 认证绕过漏洞&#xff08;CVE-2020-1957&#xff09;漏洞详情&#xff1a;复现&#xff1a; Apache Shiro 1.2.4反序列化漏洞&#xff08;CVE-2016-4437&#xff09;漏洞详情&#xff1a;复现: Apache Shiro 认证绕过漏洞&#xff08;CVE-2010-3863&…

实验二(OSPF+PPP+hub-spoke)7 5

1.合理划分IP地址&#xff1a; R1&#xff1a; R2&#xff1a; R3&#xff1a; R4&#xff1a; R5&#xff1a; R6&#xff1a; 2.启用OSPF单区域&#xff1a; R1及路由表&#xff1a; [r1]display ip routing-table protocol ospf R2及路由表&#xff1a; R3及路由表&#…

Atlassian Jira Software 9.9.1 特别版

敏捷团队首选的软件开发工具&#xff0c;Atlassian Jira Software 专为软件团队中的每位成员构建&#xff0c;可用于规划、跟踪和发布卓越的软件。 Scrum 板 利用可自定义的 Scrum 板&#xff0c;敏捷团队可集中精力尽可能迅速地交付迭代和增量价值。 看板 借助灵活的看板图&am…

【MySQL】在Linux下删除和安装MySQL

文章目录 一、前言二、检查、卸载内置环境三、获取mysql官方yum源四、正式安装MySQL服务五、登录MySQL配置my.cnf设置开机启动 一、前言 大家好久不见&#xff0c;今天开始分享关系型数据库Mysql的一些知识。 二、检查、卸载内置环境 2.1 首先使用命令查询当前mysql的运行状…

解决dbeaver查询结果乱码问题

问题描述&#xff1a; 通过dbeaver查询informinx 查询结果数据集是乱码 解决方案 &#xff1a; 右键编辑连接 在驱动属性里面新增 用户属性 NEWCODESET 值为 GBK,8859-1,819 解决数据库本身就是GBK编码&#xff0c;但是查询结果集编码不一致难题

Python+CNN 手写公式识别计算系统

系统&#xff1a;Win10 环境&#xff1a;Pycharm/Vscode Python3.7 效果图&#xff1a; 部分代码如下&#xff1a; import torch import torch.nn as nn import torch.nn.functional as F import torch.optim as optim from torchvision import datasets,transforms#定义…

5.8.9 TCP拥塞控制

5.8.9 TCP拥塞控制 我们先来说一个生活中的例子&#xff0c;在节假日到来的时候&#xff0c;由于高速公路免费通行&#xff0c;大量汽车涌上高速公路&#xff0c;最终造成交通拥堵&#xff0c;类似的情况也有可能出现在网络中&#xff0c;由于核心的交换设备在存储、带宽、速率…

ReentrantReadWriteLock读写锁

1、锁的分类 2、读写锁 读锁&#xff1a;共享锁 写锁&#xff1a;独占锁 3、代码01 class MyCache{private volatile Map<String,Object> map new HashMap<>();private ReadWriteLock rwLock new ReentrantReadWriteLock();public void put(String key,Obje…

Windows 如何打开和编辑.lnk文件

文章目录 一、背景二、查看/修改.lnk文件内容方案1&#xff1a;用type命令查看方案2&#xff1a;更改.lnk文件后缀为.txt再查看方案3&#xff1a;用记事本或NodePad打开方案4&#xff1a;使用HxD hex editor十六进制编辑器方案5&#xff1a;使用第三方库查看或编辑1. Matmaus/L…

GO语言中Protocol buffer简介

Protocol buffer 一、Protobuf简介 1.1、RPC 通信 对于单独部署&#xff0c;独立运行的微服务实例而言&#xff0c;在业务需要时&#xff0c;需要与其他服务进行通信&#xff0c;这种通信方式是进程之间的通讯方式&#xff08;inter-process communication&#xff0c;简称I…

机器学习 day23(激活函数的作用,线性激活函数的不足)

线性激活函数的局限性 如果我们将神经网络模型中的所有激活函数都设为线性激活函数&#xff0c;那整个神经网络模型就跟线性回归模型极其相似&#xff0c;且它无法拟合比线性回归模型更复杂的关系 激活函数全设为线性回归激活函数的例子 若把a带入a&#xff0c;则a可简化为…

Unity包体积优化实践

目录 简述优化前优化中assets目录资源ab包动态下发资源大小优化dll大小优化场景模型动态下载和加载优化assets目录后大小 lib目录优化目标架构裁剪代码优化代码和引用 其他优化项Shader优化Release模式编译选项 优化后 简述 在移动端App混合Unity开发的项目中&#xff0c;Unit…

VSCode配置C/C++环境(极简版)

预期结果&#xff1a; 首先安装扩展&#xff1a; 然后按照下面readme.txt中即可 链接&#xff1a;https://pan.baidu.com/s/16OV5Kr82i0gWCc4bvKs42g 提取码&#xff1a;zxcv

【模式识别目标检测】——模式识别技术车牌检测应用

目录 引入 一、模式识别主要方法 1、统计模式识别 2、基于隐马尔可夫模型识别 3、模糊模式识别 4、人工神经网络模式识别 总结 二、模式识别应用 1、车牌定位 2、车牌识别 参考文献&#xff1a; 引入 人在观察事物或现象时&#xff0c;常寻找它与其他事物或现象不同…

江苏某农商行稳健发展,软件安全推动金融服务新气象

​江苏某农商银行是全国最早成立的农商行之一。面对复杂严峻的内外部形势&#xff0c;该农商行在坚守服务“三农”与小微市场的同时&#xff0c;紧跟改革脚步&#xff0c;不断探索业务创新与数字化转型&#xff0c;实现经营稳健发展。 打造多维度数字化体系 驱动农商行创新发展…