零垃圾创建数百万个对象

如性能优化第一规则中所述,垃圾是快速代码的敌人。 通过使用垃圾收集器的服务,它不仅会破坏任何形式的确定性性能,而且我们开始在CPU高速缓存中填充垃圾,这将导致程序的高速缓存未命中。

那么,我们可以在不创建垃圾的情况下使用Java吗? 例如,在自然Java中,是否可以解决此问题:

创建10m个金融工具对象,将它们存储在地图中,检索它们并使用每个对象执行计算,而完全不会产生任何垃圾。

如果您使用Chronicle ! Chronicle提供了库,因此您可以轻松地以对象的内存映射文件形式使用堆外存储。 (有关本文的完整源代码,请参见此处 。)

让我们看一下实现上述问题的解决方案。

首先,让我们看一下如何在普通Java中执行此操作,以确保我们了解问题以及如果使用标准Java库进行实现会发生什么情况。

package zeroalloc;import org.junit.Assert;
import org.junit.Test;import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;/*** Class to demonstrate zero garbage creation.* Run with -verbose:gc -Xmx4G*/
public class CreateOnHeapTest {private static final int ITERATIONS = 10_000_000;@Testpublic void testOnHeapMap() {System.out.println("----- HASHMAP ------------------------");Map<Integer, BondVOImpl> map = new ConcurrentHashMap<>(ITERATIONS);long actualQuantity = 0;long expectedQuantity = 0;long time = System.currentTimeMillis();System.out.println("*** Entering critical section ***");for (int i = 0; i < ITERATIONS; i++) {BondVOImpl bondVo = new BondVOImpl();bondVo.setQuantity(i);map.put(Integer.valueOf(i), bondVo);expectedQuantity += i;}long putTime = System.currentTimeMillis() - time;time = System.currentTimeMillis();System.out.println("************* STARTING GET *********************");for (int i = 0; i < map.size(); i++) {actualQuantity += map.get(i).getQuantity();}System.out.println("*** Exiting critical section ***");System.out.println("Time for putting " + putTime);System.out.println("Time for getting " + (System.currentTimeMillis() - time));Assert.assertEquals(expectedQuantity, actualQuantity);printMemUsage();}public static void printMemUsage() {System.gc();System.gc();System.out.println("Memory(heap) used " + humanReadableByteCount(Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory(), true));}public static String humanReadableByteCount(long bytes, boolean si) {int unit = si ? 1000 : 1024;if (bytes < unit) return bytes + " B";int exp = (int) (Math.log(bytes) / Math.log(unit));String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp - 1) + (si ? "" : "i");return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre);}
}

这是程序的输出:

*** Entering critical section ***
[GC (Allocation Failure)  98816K->92120K(125952K), 0.0317021 secs]
[Full GC (Ergonomics)  92120K->91917K(216576K), 0.2510530 secs]
[GC (Allocation Failure)  125197K->125430K(224256K), 0.0449051 secs]
[GC (Allocation Failure)  166390K->166686K(244224K), 0.0504341 secs]
[Full GC (Ergonomics)  166686K->165777K(387072K), 0.6243385 secs]
[GC (Allocation Failure)  226705K->226513K(388096K), 0.0785121 secs]
[GC (Allocation Failure)  293073K->293497K(392704K), 0.0825828 secs]
[Full GC (Ergonomics)  293497K->292649K(591872K), 1.2479519 secs]
[GC (Allocation Failure)  359209K->359433K(689664K), 0.0666344 secs]
[GC (Allocation Failure)  449033K->449417K(695296K), 0.1759746 secs]
[GC (Allocation Failure)  539017K->539385K(747008K), 0.1907760 secs]
[GC (Allocation Failure)  632569K->633009K(786944K), 0.2293778 secs]
[Full GC (Ergonomics)  633009K->631584K(1085952K), 2.1328028 secs]
[GC (Allocation Failure)  724768K->723368K(1146368K), 0.3092297 secs]
[GC (Allocation Failure)  827816K->825088K(1174016K), 0.3156138 secs]
[GC (Allocation Failure)  929536K->929952K(1207296K), 0.3891754 secs]
[GC (Allocation Failure)  1008800K->1009560K(1273856K), 0.4149915 secs]
[Full GC (Ergonomics)  1009560K->1007636K(1650688K), 3.4521240 secs]
[GC (Allocation Failure)  1086484K->1087425K(1671680K), 0.3884906 secs]
[GC (Allocation Failure)  1195969K->1196129K(1694208K), 0.2905121 secs]
[GC (Allocation Failure)  1304673K->1305257K(1739776K), 0.4291658 secs]
[GC (Allocation Failure)  1432745K->1433137K(1766912K), 0.4470582 secs]
[GC (Allocation Failure)  1560625K->1561697K(1832960K), 0.6003558 secs]
[Full GC (Ergonomics)  1561697K->1558537K(2343936K), 4.9359721 secs]
[GC (Allocation Failure)  1728009K->1730019K(2343936K), 0.7616385 secs]
[GC (Allocation Failure)  1899491K->1901139K(2413056K), 0.5187234 secs]
[Full GC (Ergonomics)  1901139K->1897477K(3119616K), 5.7177263 secs]
[GC (Allocation Failure)  2113029K->2114505K(3119616K), 0.6768888 secs]
[GC (Allocation Failure)  2330057K->2331441K(3171840K), 0.4812436 secs]
[Full GC (Ergonomics)  2331441K->2328578K(3530240K), 6.3054896 secs]
[GC (Allocation Failure)  2600962K->2488834K(3528704K), 0.1580837 secs]
*** Exiting critical section ***
Time for putting 32088
Time for getting 454
[GC (System.gc())  2537859K->2488834K(3547136K), 0.1599314 secs]
[Full GC (System.gc())  2488834K->2488485K(3547136K), 6.2759293 secs]
[GC (System.gc())  2488485K->2488485K(3559936K), 0.0060901 secs]
[Full GC (System.gc())  2488485K->2488485K(3559936K), 6.0975322 secs]
Memory(heap) used 2.6 GB

跳出此问题的两个要点是:一是垃圾回收的数量和开销(显然可以调整),二是使用了2.6GB的堆数量。 简而言之,无法摆脱它,该程序会产生大量垃圾。

我们这次使用ChronicleMap尝试完全相同的操作。

这是解决问题的代码:

package zeroalloc;import net.openhft.chronicle.map.ChronicleMap;
import net.openhft.chronicle.map.ChronicleMapBuilder;
import net.openhft.lang.values.IntValue;
import org.junit.Assert;
import org.junit.Test;import java.io.File;
import java.io.IOException;/*** Class to demonstrate zero garbage creation.* Run with -verbose:gc* To run in JFR use these options for best results* -XX:+UnlockCommercialFeatures -XX:+FlightRecorder*/
public class CreateChronicleTest {private static final int ITERATIONS = 10_000_000;@Testpublic void demoChronicleMap() throws IOException, InterruptedException {System.out.println("----- CHRONICLE MAP ------------------------");File file = new File("/tmp/chronicle-map-" + System.nanoTime() + ".map");file.deleteOnExit();ChronicleMapBuilder<IntValue, BondVOInterface> builder =ChronicleMapBuilder.of(IntValue.class, BondVOInterface.class).entries(ITERATIONS);try (ChronicleMap<IntValue, BondVOInterface> map =builder.createPersistedTo(file)) {final BondVOInterface value = map.newValueInstance();final IntValue key = map.newKeyInstance();long actualQuantity = 0;long expectedQuantity = 0;long time = System.currentTimeMillis();System.out.println("*** Entering critical section ***");for (int i = 0; i < ITERATIONS; i++) {value.setQuantity(i);key.setValue(i);map.put(key, value);expectedQuantity += i;}long putTime = (System.currentTimeMillis()-time);time = System.currentTimeMillis();for (int i = 0; i < ITERATIONS; i++) {key.setValue(i);actualQuantity += map.getUsing(key, value).getQuantity();}System.out.println("*** Exiting critical section ***");System.out.println("Time for putting " + putTime);System.out.println("Time for getting " + (System.currentTimeMillis()-time));Assert.assertEquals(expectedQuantity, actualQuantity);printMemUsage();} finally {file.delete();}}public static void printMemUsage(){System.gc();System.gc();System.out.println("Memory(heap) used " + humanReadableByteCount(Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory(), true));}public static String humanReadableByteCount(long bytes, boolean si) {int unit = si ? 1000 : 1024;if (bytes < unit) return bytes + " B";int exp = (int) (Math.log(bytes) / Math.log(unit));String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp-1) + (si ? "" : "i");return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre);}
}

这是程序的输出:

[GC (Allocation Failure)  33280K->6595K(125952K), 0.0072065 secs]
[GC (Allocation Failure)  39875K->12177K(125952K), 0.0106678 secs]
[GC (Allocation Failure)  45457K->15289K(125952K), 0.0068434 secs]
[GC (Allocation Failure)  48569K->18357K(159232K), 0.0098287 secs]
[GC (Allocation Failure)  84917K->21008K(159232K), 0.0156393 secs]
*** Entering critical section ***
*** Exiting critical section ***
Time for putting 8554
Time for getting 4351
[GC (System.gc())  36921K->21516K(230400K), 0.0331916 secs]
[Full GC (System.gc())  21516K->15209K(230400K), 0.0630483 secs]
[GC (System.gc())  15209K->15209K(230912K), 0.0006491 secs]
[Full GC (System.gc())  15209K->15209K(230912K), 0.0234045 secs]
Memory(heap) used 18.2 MB

显然,这里的要点是,关键部分没有 GC,整个程序仅使用18MB的堆。 我们设法创建了一个程序,该程序通常会产生千兆字节的垃圾,而根本不会产生任何垃圾。

关于时间的注意事项

ChronicleMap显然不是ConcurrentHashMap的替代品,它们的用法有很大不同,并且超出了本文的讨论范围。 但是功能上的主要区别是ChronicleMap是持久的,并且可以在许多JVM之间共享。 (ChronicleMap还具有可以复制tcp的功能。)尽管如此,如果除了确保我们处于同一个球场之外,快速比较时间比较有趣。 ChronicleMap的投放速度更快,从32秒提高到8.5秒。 但是ConcurrentHashMap中的大部分时间都花在GC上,并且可能会在某种程度上进行调整。 ConcurrentHashMap的获取速度比4.3s快了0.5s。 不过,在其他运行中,由于该部分中发生了GC,因此我看到ConcurrentHashMap占用了7s的时间。 即使ChronicleMap所做的工作要多得多,但实际上由于缺少垃圾而使计时与ConcurrentHashMap相当。

重新启动程序

ChronicleMap真正发挥作用的地方是重新启动。 假设您的程序崩溃了,您需要重新计算与之前相同的计算。 对于ConcurrentHashMap,我们将不得不完全按照之前的方法重新填充地图。 使用ChronicleMap,由于地图是持久的,因此只需将地图指向现有文件,然后重新运行计算以产生totalQuantity。

摘要

并发哈希图 编年史
gc暂停 许多 没有
更新时间 32秒 8秒
读取允许gc 7秒 4秒
不读gc 0.5秒 4秒
堆大小 2.6GB 18MB
坚持不懈 没有
快速重启 没有

翻译自: https://www.javacodegeeks.com/2015/03/creating-millions-of-objects-with-zero-garbage.html

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

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

相关文章

[算法]单链表专题

如何判断链表环的入口位置&#xff1f; 一个指针从头开始单步走&#xff0c;一个指针从第一次相遇位置开始单步走&#xff0c;再相遇的位置就是环入口&#xff0c;证明如下&#xff1a; 设链表头到环入口位置距离为a&#xff0c;入口位置到第一次相遇位置为b&#xff0c;相遇位…

批准Oracle IDM中的特定Web服务

关于Web服务端点的快速发布&#xff0c;OIM和SOA在与批准有关的场景中使用了Web服务端点- 基本内容&#xff0c;但对于初学者可能有用 。 Oracle IDM与SOA套件集成并利用其提供与批准相关的功能&#xff08;说实话&#xff0c;SOA相当丰富&#xff0c;并且也被用作Web服务连接…

Oracle15001,Oracle11gR2RAC环境DBCA创建数据库报错ORA-15055ORA-15001

在Oracle 11gR2 GridInfrastructure和Database软件安装完成之后&#xff0c;执行DBCA创建数据库到30%的时候报如下错误&#xff0c;点击OK后提示忽略并问题现象:在Oracle 11gR2 GridInfrastructure和Database软件安装完成之后&#xff0c;执行DBCA创建数据库到30%的时候报如下错…

linux 下访问mysql

1&#xff1a;先进到root:/# /usr/local/mysql/bin/2&#xff1a;root:/# mysql -u root -p Enter password: 转载于:https://www.cnblogs.com/gaoyinghui/p/3255148.html

针对新手的Java EE7和Maven项目–第8部分

第1部分 &#xff0c; 第2部分 &#xff0c; 第3部分 &#xff0c; 第4部分 &#xff0c; 第5部分 &#xff0c; 第6部分 &#xff0c; 第7部分 第8部分 自上一篇文章以来&#xff0c;这一系列教程已经有很长时间了。 是时候恢复并在我们的简单项目中添加新功能了。 正…

oracle_home path,ORACLE_HOME迁移后需要设置LD_LIBRARY_PATH环境变量

而设置LD_LIBRARY_PATH后&#xff0c;问题解决&#xff1a;[orat3hpserver2 ~]$ export LD_LIBRARY_PATH$ORACLE_HOME/lib[orat3hpserver2 ~]$ sqlplus / AS sysdbaSQL*Plus: Release 10.2.0.4.0 - Production ON Sun Mar 18 16:10:57 2012Copyright (c) 1982, 2007, Oracle. A…

栈的链式存储及其基本运算

#include <stdio.h> #include <stdlib.h> #define M 10typedef struct stnode {char data;struct stnode *next; }LinkStack;void InitStack(LinkStack *&ls) //初始化栈 {lsNULL; }void PushStack(LinkStack *&ls,char x)//进栈 {LinkStack *p;p(LinkSta…

oracle的导出参数statistic,使用expdp导出时评估所需存储容量大小

我们在使用expdp进行数据导出时&#xff0c;可以事先评估需要存储大小容量(bytes)&#xff0c;Oracle可以通过两种方式进行容量估算:[more]1)、通过数据块数量2)、通过统计信息中记录的内容估算具体是通过制定参数estimate_only和estimate来评估导出的性能参数estimate_onlyy|n…

玩Weld-Probe –一站式查看CDI的所有方面

焊接3.0.0.Alpha4被释放 &#xff0c;而我一直坐在在DevConf.CZ一间会议室。 Jozef Hartinger&#xff08; jozefhartinger &#xff09;或多或少地在几分钟前告诉我有关此最新版本的新功能的信息。 有一个特别的功能真正引起了我的注意&#xff0c;它是新的焊接探针机制。 什…

排列、组合问题(递归)

这里主要介绍字符串排列组合问题,高中数学常见的题目,不用详细介绍&#xff0c;看例子就可以解决问题 "1212" 全排列结果为 1212&#xff0c;1221&#xff0c;1122&#xff0c;2112&#xff0c;2121&#xff0c;2211 组合结果是 1,2,12 我所理解的排列组合结果是…

oracle日志文件大小规则,修改oracle日志文件大小

1、创建2个新的日志组alter database add logfile group 4 (D:\ORACLE\ORADATA\ORADB\REDO04_1.LOG) size 1024k;alter database add logfile group 5 (D:\ORACLE\ORADATA\ORADB\REDO05_1.LOG) size 1024k;2、切换当前日志到新的日志组alter system switch logfile;alter syste…

Java开发工具可以促进编程!

Java开发人员通常尝试找到快速有效地编写高质量Java代码的方法&#xff0c;以使他们的编程工作更轻松。 由于情况发生了变化&#xff0c;因此出现了越来越多的工具。 因此&#xff0c;下面列出了大多数开发人员已经使用&#xff0c;将来使用或一定会使用的有用工具。 该列表包括…

linux cmake装在自己目录下,如何在Linux下安装cmake

全部展开OpenCV 2.2和更高版本需要使用Cmake生成生成文件&#xff0c;因此需要先安装cmake. 还有其他需要先安装cmake的软件1. 在Linux环境中打开Web浏览器&#xff0c;输入URL:mac cmake gui&#xff0c;找到最新版本的位置. 通常&#xff0c;发布了两个版本的开源软件: “源分…

Java Bootstrap:Dropwizard与Spring Boot

如何在尽可能短的时间内使准备就绪的Java应用程序投入生产&#xff1f; 我不是一个早起的人&#xff0c;所以有时需要一些时间才能启动“所有系统”提示。直到不久之前&#xff0c;这对于Java应用程序来说都是正确的&#xff0c;但是与发明贪睡功能不同闹钟&#xff0c;我们将在…

linux 查看libusb版本,linux / libusb获取usb设备路径

我使用libusb来枚举一些usb设备.现在我想获得“设备路径”.我认为这不是usb device-path,因为我没有成功使用谷歌.如果我用linux连接usb设备,我会在dmesg中收到一条消息,这里有一些带有usb温度传感器的“设备路径”的例子(类似于this)&#xff1a;H_301_3直接到usb端口&#xf…

如何使用Apache Drill分析高度动态的数据集

当今的数据是动态的&#xff0c;并由应用程序驱动。 由诸如Web /社交/移动/ IOT等行业趋势驱动的新业务应用时代的增长正在生成具有新数据类型和新数据模型的数据集。 这些应用程序是迭代的&#xff0c;并且关联的数据模型通常是半结构化的&#xff0c;无模式的且不断发展的。 …

MVC中不能使用原生态的#include ,可替代的解决方案

<!--#include file"../stuff/foo/box.aspx"--> 1.可以用 <%: Html.Partial("~/Views/foo/box.ascx") %>OR <% Html.RenderPartial("~/Views/foo/box.ascx"); %> 2. Html.Raw(File.ReadAllText(Server.MapPath("~/html/te…

linux备份日志文件脚本,Linux篇:Shell脚本实现Gitlab双备份

01 前言最近成功从架构组拿到了Gitlab的管理权限&#xff0c;第一件事就是想着如何备份&#xff0c;以防数据丢失背大锅&#xff0c;于是在网上搜索一番&#xff0c;发现一段非常赞的备份脚本&#xff0c;记录照着操作一下&#xff1a;尤其是第二篇文章博主&#xff0c;有非常多…

物理数据模型(PDM)-概念数据模型 (CDM)-面向对象模型 (OOM):适用于已经设计好数据库表结构了。...

步骤如下&#xff1a; 一、反向生成物理数据模型PDM 开发环境 PowerDesigner 15 ,SQL Server2005 &#xff08;1&#xff09;在开始逆向生成PDM图之前&#xff0c;需要为指定的数据库创建ODBC数据源。以Windows xp操作系统为例&#xff0c;选择“开始”/“运行”命令&#xff0…

带有Hibernate OGM的NoSQL –第二部分:查询数据

1月底发布了Hibernate OGM的第一个最终版本之后&#xff0c;团队一直在忙于制作一系列教程式博客&#xff0c;使您有机会轻松地从Hibernate OGM重新开始。 第一部分是关于设置和保留您的第一个实体 。 在第二部分中&#xff0c;您将学习如何查询数据。 Hibernate OGM将使您以几…