堆上与堆外的内存使用情况

总览

最近有人问我在Java中使用堆内存的好处和智慧。 面临相同选择的其他人可能会对这些答案感兴趣。

堆外内存没什么特别的。 线程堆栈,应用程序代码,NIO缓冲区都在堆外。 实际上,在C和C ++中,您只有非托管内存,因为默认情况下它没有托管堆。 Java中托管内存或“堆”的使用是该语言的一个特殊功能。 注意:Java不是执行此操作的唯一语言。

新的Object()vs对象池vs Off堆内存

新的Object()

在Java 5.0之前,使用对象池非常流行。 创建对象仍然非常昂贵。 但是,从Java 5.0开始,对象分配和垃圾清理变得便宜得多,并且开发人员发现,通过删除对象池并仅在需要时创建新对象,它们可以提高性能,并简化代码。 在Java 5.0之前,几乎所有对象池(甚至是使用对象的对象池)都提供了改进,从Java 5.0来看,只有昂贵的对象才有意义,例如线程,套接字和数据库连接。

对象池

在低延迟空间中,显而易见的是,通过减少对CPU缓存的压力,回收可变对象可以提高性能。 这些对象必须具有简单的生命周期和简单的结构,但是使用它们可以看到性能和抖动方面的显着改善。

使用对象池的另一个有意义的领域是当使用许多重复的对象加载大量数据时。 随着内存使用量的显着减少以及GC必须管理的对象数量的减少,您看到了GC时间的减少和吞吐量的增加。

与使用同步HashMap相比,这些对象池的重量更轻,因此它们仍然可以提供帮助。

以这个StringInterner类为例。 您将所需文本的可循环使用的可变StringBuilder作为字符串传递给它,它将提供匹配的字符串。 传递String效率不高,因为您已经创建了对象。 StringBuilder可以回收。

注意:此结构具有一个有趣的属性,除了最低Java保证所提供的功能外,不需要任何其他线程安全功能(例如volatile或sync)。 也就是说,您可以正确地看到String中的final字段,并且只能读取一致的引用。

public class StringInterner {private final String[] interner;private final int mask;public StringInterner(int capacity) {int n = Maths.nextPower2(capacity, 128);interner = new String[n];mask = n - 1;}private static boolean isEqual(@Nullable CharSequence s, @NotNull CharSequence cs) {if (s == null) return false;if (s.length() != cs.length()) return false;for (int i = 0; i < cs.length(); i++)if (s.charAt(i) != cs.charAt(i))return false;return true;}@NotNullpublic String intern(@NotNull CharSequence cs) {long hash = 0;for (int i = 0; i < cs.length(); i++)hash = 57 * hash + cs.charAt(i);int h = (int) Maths.hash(hash) & mask;String s = interner[h];if (isEqual(s, cs))return s;String s2 = cs.toString();return interner[h] = s2;}
}

堆外内存使用率

使用堆外内存和使用对象池都有助于减少GC暂停,这是它们唯一的相似之处。 对象池适用于短暂的可变对象,创建对象的开销很大,而存在很多重复的永久对象则是不可变的。 中度活泼的可变对象或复杂的对象更有可能由GC处理。 但是,中型到长寿命的可变对象受堆内存解决的许多方式的困扰。

堆外内存提供;

  • 可扩展至大型内存,例如超过1 TB且大于主内存。
  • 名义上对GC暂停时间的影响。
  • 在进程之间共享,减少JVM之间的重复,并使分裂JVM更容易。
  • 持久性,可以更快地重新启动或回复测试中的生产数据。

在设计系统方面,堆外内存的使用为您提供了更多选择。 最重要的改进不是性能,而是确定性。

堆外和测试

高性能计算中的最大挑战之一是再现难以理解的错误,并能够证明已解决了这些错误。 通过以持久方式将所有输入事件和数据存储在堆外,您可以将关键系统变成一系列复杂的状态机。 (或者在简单的情况下,只有一个状态机)以这种方式,您可以在测试和生产之间获得可重现的行为和性能。

许多投资银行都使用此技术对一天中的任何事件可靠地重播系统,并确切地说明了该事件按原样处理的原因。 更重要的是,一旦你有了一个位置,你可以证明你有固定发生在生产,而不是发现问题,并希望这是问题的问题。

确定性行为与确定性行为一起出现。 在测试环境中,您可以按照实际的时间重播事件,并显示期望在生产中获得的延迟分布。 如果硬件不同,则无法重现某些系统抖动,但是从统计角度看,您可能会非常接近。 为了避免花一天时间重放一天的数据,您可以添加一个阈值。 例如,如果事件之间的时间超过10毫秒,则您可能只能等待10毫秒。 这样一来,您可以在不到一个小时的时间内按实际时间重播一天的事件,并查看您的更改是否改善了延迟分配。

通过降低级别,您不会失去“一次编译,随处运行”的某些功能吗?

在某种程度上,这是正确的,但远没有您想像的要多。 当您靠近处理器工作时,您将更加依赖处理器或OS的行为方式。 幸运的是,大多数系统使用AMD / Intel处理器,就其提供的低级别保证而言,甚至ARM处理器也变得更加兼容。 操作系统之间也存在差异,并且这些技术在Linux上比Windows上更有效。 但是,如果您在MacOSX或Windows上进行开发并使用Linux进行生产,则应该没有任何问题。 这就是我们在高频交易中所做的。

我们通过使用堆产生了哪些新问题?

没有什么是免费的,堆外情况就是这样。 堆外的最大问题是您的数据结构变得不太自然。 您或者需要一个可以直接映射到堆外的简单数据结构,或者需要一个序列化和反序列化的复杂数据结构以使其脱离堆。 显然使用序列化有其自身的麻烦和性能损失。 因此,使用序列化要比在堆对象上慢得多。

在金融世界中,最昂贵的数据结构是扁平且简单的,充满了原语,可以很好地在堆外映射,几乎没有开销。 但是,这并不适用于所有应用程序,您可以获得复杂的嵌套数据结构,例如图形,最终还必须在堆上缓存某些对象。

另一个问题是,JVM限制了您可以使用的系统数量。 您不必担心JVM会使系统过载太多。 有了堆外处理,就解除了一些限制,您可以使用比主内存大得多的数据结构,并且开始担心如果要这样做,您将拥有哪种磁盘子系统。 例如,您不希望分页至具有80 IOPS的HDD,而您可能希望拥有80,000 IOPS(每秒输入/输出操作)或更高(即快1000倍)的SSD。

OpenHFT如何提供帮助?

OpenHFT有许多库可以隐藏您实际上正在使用本机内存来存储数据的事实。 这些数据结构是持久的,几乎没有垃圾就可以使用。 这些用于不需少量收集即可全天运行的应用程序中

编年史队列 -持久的事件队列。 支持同一台机器上跨JVM的并发编写器,以及跨机器并发读取器。 微秒级的延迟和每秒数百万条消息的持续吞吐量。

编年史地图 –键值地图的本机或持久存储。 可以在同一台机器上的JVM之间共享,通过UDP或TCP复制和/或通过TCP远程访问。 微秒级延迟和持续的读/写速率,每台机器每秒可进行数百万次操作。

线程亲和性 –将关键线程绑定到隔离的内核或逻辑CPU,以最大程度地减少抖动。 可以将抖动降低1000倍。

使用哪个API?

如果您需要记录每个事件->编年史队列

如果您只需要最新结果作为唯一键->编年史地图

如果您关心20微秒抖动->线程亲和力

结论

堆外内存可能会带来挑战,但也会带来很多好处。 您可以在其中看到最大的收益,并与其他为实现可伸缩性而引入的解决方案进行比较。 与在堆缓存,消息传递解决方案或进程外数据库上使用分区/分片相比,堆外可能更简单,更快。 通过提高速度,您可能会发现不再需要为获得所需性能所需的一些技巧。 例如,堆外解决方案可以支持对OS的同步写入,而不必以异步方式执行写入操作,而存在数据丢失的风险。

但是,最大的收益就是启动时间,从而使您的生产系统重新启动的速度更快。 例如,映射到1 TB数据集中可能需要10毫秒,并且通过重播每个事件以使您每次都获得相同的行为,可以简化测试的可重复性。 这使您可以创建可以依靠的质量体系。

翻译自: https://www.javacodegeeks.com/2014/12/on-heap-vs-off-heap-memory-usage.html

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

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

相关文章

从CSS实现正片叠底看=混合模式mix-blend-mode

兼容性&#xff1a;这个东西说多了也没意思&#xff0c;像HTML5和CSS3这种兼容性时刻变化的东东&#xff0c;我们最好在自己支持的设备上实验&#xff0c;不支持&#xff0c;就在想办法呗&#xff0c;这个东西就是为了方便和好玩 所有属性&#xff1a; mix-blend-mode: normal…

实现对gridview删除行时弹出确认对话框的四种方法

实现对gridview删除行时弹出确认对话框的四种方法 在.net2.0中&#xff0c;实现对gridview删除行时弹出确认对话框的四种方法 1&#xff0c;GridView中如何使用CommandField删除时&#xff0c;弹出确认框? 在VS2005提供的GridView中我们可以直接添加一个CommandField删除列&am…

我最喜欢的Java拼图2 + 1 = 4

这是我当前最喜欢的Java难题。 您如何获取代码来执行此操作&#xff1f; Integer b 2; Integer c 1;System.out.println("bc : " (bc) ); // output: bc : 4 !!Sytem.out.println&#xff08;&#xff09;没有技巧&#xff0c;即您将能够在调试器中看到相同的值。…

CSS3盒模型温故

CSS有一种基础设计模式叫盒模型&#xff0c;定义了Web页面中的元素是如何看做盒子来解析的。每一个盒子有不同的展示界面&#xff0c;下面就来介绍盒模型&#xff0c;主要有一下几种盒模型&#xff1a;inline、inline-block、block、table、absolute position、float。浏览器把…

SSL与WildFly 8和Undertow

我一直在研究WildFly 8的一些安全性主题&#xff0c;偶然发现了一些配置文档&#xff0c;这些文档没有很好地记录。 其中之一是新Web子系统Undertow的TLS / SSL配置。 有许多关于较旧的Web子系统的文档&#xff0c;并且确实仍然可以使用&#xff0c;但是这里是使用新方法进行配…

伸展树

伸展树结合了二叉搜索树BST及二叉平衡树AVL的旋转特点&#xff0c;在每一次访问到某节点时都通过旋转将该节点往上推一位&#xff0c;由于没有保存高度信息因为空间复杂度稍优于二叉平衡树。伸展树的插入&#xff0c;删除&#xff0c;搜索的平均时间复杂度均为o(logn)&#xff…

CSS属性选择器温故-4

1.属性选择器就是通过元素属性来找到元素 2.属性选择器语法 CSS3遵循了惯用的编码规则&#xff0c;通配符的使用提高了样式表的书写效率&#xff0c;也使CSS3的属性选择器更符合编码习惯 3.浏览器兼容性 CSS选择器总结&#xff1a;CSS选择器和jQuery的选择器非常相似&#xff…

如何封装Spring bean

据我所知&#xff0c;Spring Framework除了具有单独的上下文之外&#xff0c;没有提供任何封装Spring bean的机制。 因此&#xff0c;当您在Spring的Inversion of Control容器中注册了公共类时&#xff0c;可以通过相同的上下文配置将其自动连接到任何Spring bean中。 这非常强…

分享下自己的EmpireofCode进攻策略 https://empireofcode.com/ https://empireofcode.com/game/#

# 没什么用&#xff0c;该游戏的模块调用不友好&#xff0c;取数据难import queue from battle import commander # import mathunit_client commander.Client() doing_last_order True towerid [] towerrg [] towerfr [] towerps [] tower_id 0 towers [] safe_posi[4…

Python多篇新闻自动采集

昨天用python写了一个天气预报采集&#xff0c;今天趁着兴头写个新闻采集的。 目标是&#xff0c;将腾讯新闻主页上所有新闻爬取下来&#xff0c;获得每一篇新闻的名称、时间、来源以及正文。 接下来分解目标&#xff0c;一步一步地做。 步骤1&#xff1a;将主页上所有链接爬取…

使用ADF BC管理保存点

在使用ADF BC时&#xff0c;我们通常依赖于在数据库中执行DML操作的框架。 在DBTransaction提交周期内&#xff0c;该框架正确地在数据库中进行了所有必要的更新。 很酷的事情是&#xff0c;在这种情况下&#xff0c;数据库事务将被自动管理。 因此&#xff0c;如果出现问题&am…

sql优化(转)

(转)SQL 优化原则一、问题的提出 在应用系统开发初期&#xff0c;由于开发数据库数据比较少&#xff0c;对于查询SQL语句&#xff0c;复杂视图的的编写等体会不出SQL语句各种写法的性能优劣&#xff0c;但是如果将应用 系统提交实际应用后&#xff0c;随着数据库中数据的增加&a…

2017-12-04HTML table布局

<!DOCTYPE html> <html> <head lang"en"> <meta charset"UTF-8"> <title>table布局</title> </head> <body marginwidth"0px" marginheight"0px"> <table width"…

Java EE 8发生了什么? (第2部分)

Java EE 8的工作仍处于初期阶段&#xff0c;预计在来年会紧跟潮流&#xff0c;我们将看到专家组的形成完成&#xff0c;围绕用例/功能的更多讨论&#xff0c;许多JIRA&#xff0c;以及各种规范的草案版本&#xff08;本会很有趣&#xff01;&#xff09;。 在第1部分中 &#…

foreach语句的的解析

我这个虾米&#xff0c;今天才知道foreach语句是这样解析的&#xff0c;惭愧啊&#xff01;幸好我最新在原生态的学习这门编程语言。 //程序中我们这样写foreachforeach (Person item in Persons){Console.WriteLine(item);} //其实如果要使用foreach,需要实现IEnumerator接口&…

滚动条位置判断

//获取滚动条距离顶部位置function getScrollTop() { var scrollTop 0; if (document.documentElement && document.documentElement.scrollTop) { scrollTop document.documentElement.scrollTop; } else if (document.body) { scrollTop d…

如何处理Java注释

Java 8的很酷的新功能之一就是对lambda表达式的支持。 Lambda表达式在很大程度上依赖于FunctionalInterface 注释 。 在本文中&#xff0c;我们将介绍注释以及如何处理它们&#xff0c;以便您可以实现自己的出色功能。 注解 Java 5中添加了注释 。Java语言附带了一些预定义的…

(转)MFC技巧学习五

51. 如何获得其他程序的图标,并显示在View中 [问题提出] 有的时候,如:类资源管理器会遇到获得程序图标并显示的操作,如何实现呢? [解决方法] SDK函数SHGetFileInfo来获得有关文件的很多信息:如大小图标,属性,类型等.  [程序实现] 建立名为My的SDI工程.在OnPaint()函数中…

使用navicat premium将数据库从Oracle迁移到SQL Server,或从Oracle迁移到MySQL

有时候我们有迁移数据库的需求&#xff0c;例如从Oracle迁移到SQL Server&#xff0c;或者从MySQL迁移到Oracle。 很多江湖好汉一时不知如何手工操作&#xff0c;所幸的是Navicat提供了迁移的自动化操作界面。 当然&#xff0c;Navicat的数据库迁移无法做到完美&#xff0c;一些…

书评:Mockito Essentials

Sujoy Acharya的Mockito Essentials副标题&#xff08; Packt Publishing &#xff0c;2014年10月&#xff09;是&#xff1a;“实用指南&#xff0c;可帮助您使用Mockito进行单元测试并开始运行。” Mockito Essentials中的前言和七章涵盖大约190个实质性页面。 前言 在序言中…