当前位置: 首页 > news >正文

电子商务网站建设方案范文网络营销产品概念

电子商务网站建设方案范文,网络营销产品概念,wordpress 表格数据,创建网站app问题 代际屏障为什么会影响JVM的性能? 基础知识 大部分的垃圾回收期都是分代的,或者是分区域的。如果任何垃圾收集器想要收集托管堆的部分而不触及整个堆,那么它必须了解哪些引用指向该收集部分。否则,它无法可靠地判断该收集部分中什么是…

问题

代际屏障为什么会影响JVM的性能?

基础知识

大部分的垃圾回收期都是分代的,或者是分区域的。如果任何垃圾收集器想要收集托管堆的部分而不触及整个堆,那么它必须了解哪些引用指向该收集部分。否则,它无法可靠地判断该收集部分中什么是可访问的,因此必须保守地假设一切都是可访问的……​ 这使得它处于没有任何东西可以被视为垃圾的境地。其次,如果它移动了该收集部分中的任何对象,它希望了解要更新哪些位置 — 这主要涉及在处理收集部分时不会被访问的“外部”指针。

那垃圾回收器是如何解决这个难题的呢?其实只要将堆分成多个部分就可以,将堆分成几部分的最简单(也是最有效的)方法是按年龄隔离对象,即引入代数。这里的关键思想是弱代假说,即“新对象会早逝”。利用弱代假说的实际情况是,在标记收集器时,性能取决于幸存对象的数量。这意味着,我们可以有一个年轻代,其中所有东西都基本死了,我们可以快速甚至更频繁地处理它,而老一代则被放在一边。

但是,在单独收集年轻代时,可能需要注意从老代到年轻代的引用。老年代通常与整个堆一起收集,年轻代对老年代的引用可以从跟踪中省略。年轻代对年轻代和老年代到老年代的引用也是如此,因为它们的引用将在同一次收集中被访问。
在这里插入图片描述

以 OpenJDK 的 Parallel GC 为例,它借助卡表记录老年代对年轻代的引用:卡表是横跨老年代的粗略位图。存储时,需要翻转该卡表中的一位。该位意味着老年代“卡片下方”的部分可能具有指向年轻代的指针,并且在收集年轻代时需要对其进行扫描。要使所有这些工作正常,引用存储必须通过写屏障进行增强,即执行卡表管理的小代码片段。

实验

用例源码

@State(Scope.Benchmark)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Fork(value = 3, jvmArgsAppend = {"-Xms4g", "-Xmx4g", "-Xmn2g"})
@Threads(Threads.MAX)
public class HashWalkBench {@Param({"16", "256", "4096", "65536", "1048576", "16777216"})int size;Map<String, String> map;@Setuppublic void setup() throws Exception {create();System.gc();}private void create() {String[] keys = new String[size];String[] values = new String[size];for (int c = 0; c < size; c++) {keys[c] = "Key" + c;values[c] = "Value" + c;}map = new HashMap<>(size);for (int c = 0; c < size; c++) {String key = keys[c];String val = values[c];map.put(key, val);}}@Benchmarkpublic void walk(Blackhole bh) {for (Map.Entry<String, String> e : map.entrySet()) {bh.consume(e.getKey());bh.consume(e.getValue());}}
}

运行结果

Benchmark             (size)  Mode  Cnt       Score      Error  Units# Epsilon
HashWalkBench.walk        16  avgt   15       0.238 ±    0.005  us/op
HashWalkBench.walk       256  avgt   15       3.638 ±    0.072  us/op
HashWalkBench.walk      4096  avgt   15      59.222 ±    1.974  us/op
HashWalkBench.walk     65536  avgt   15    1102.590 ±    4.331  us/op
HashWalkBench.walk   1048576  avgt   15   19683.680 ±  195.086  us/op
HashWalkBench.walk  16777216  avgt   15  328319.596 ± 7137.066  us/op# Parallel
HashWalkBench.walk        16  avgt   15       0.240 ±    0.001  us/op
HashWalkBench.walk       256  avgt   15       3.679 ±    0.078  us/op
HashWalkBench.walk      4096  avgt   15      64.778 ±    0.275  us/op
HashWalkBench.walk     65536  avgt   15    1377.634 ±   28.132  us/op
HashWalkBench.walk   1048576  avgt   15   25223.994 ±  853.601  us/op
HashWalkBench.walk  16777216  avgt   15  400679.042 ± 8155.414  us/op

汇编

1.58%    0.91%   ...a4e2c: mov    %edi,0x18(%r9)       ; %r9 = iterator, 0x18(%r9) = field
0.27%    0.33%   ...a4e30: mov    %r9,%r11             ; r11 = &iterator
0.26%    0.38%   ...a4e33: shr    $0x9,%r11            ; r11 = r11 >> 9
0.13%    0.20%   ...a4e37: movabs $0x7f2c535aa000,%rbx ; rbx = card table base
0.58%    0.57%   ...a4e41: mov    %r12b,(%rbx,%r11,1)  ; put 0 to (rbx+r11)

如上述执行结果所述,字符串数据是存储在隐式实例化HashMap.EntrySetIterator的当前条目的字段中,且从上述结果可以观察到具体的屏障,具体如下:

  • 卡标记设置整个字节,而不仅仅是一个位。这避免了同步:大多数硬件可以自动执行字节存储,而无需触及周围的数据。这使得卡表比理论上的更强大,但仍然相当密集:每 512 字节堆有 1 个卡表字节,注意移位 9。
  • 屏障是无条件发生的,而我们只需要记录老年代对年轻代的引用。这似乎很实用:我们在热路径上没有多余的分支,并且我们交换跨越​​整个堆的卡片表,而不仅仅是旧堆。考虑到卡片表的密度,我们只会引入一小部分额外的占用空间。这也有助于在可以自我调整的收集器中移动年轻代和老年代之间的短暂边界,而无需修补代码。
  • 卡表地址被编码在生成的代码中,这又很实用,因为它是一个本机不可移动的结构。这节省了内存负载,因为否则我们必须从某个地方轮询卡表地址。
  • 卡标记“设置”实际上被编码为“0”。这同样很实用,因为我们可以重用零寄存器(尤其是在明确具有零寄存器的架构上)来获取源操作数。稍后在本地 GC 代码中,卡表初始化使用什么值(0 或 1)并不重要。

我们可以通过-prof perfnorm来进一步分析,执行结果如下:

Benchmark                                  (size)  Mode  Cnt    Score    Error  Units# Epsilon
HashWalkBench.walk                        1048576  avgt   15    0.019 ±  0.001  us/op
HashWalkBench.walk:L1-dcache-load-misses  1048576  avgt    3    0.389 ±  0.495   #/op
HashWalkBench.walk:L1-dcache-loads        1048576  avgt    3   25.439 ±  2.411   #/op
HashWalkBench.walk:L1-dcache-stores       1048576  avgt    3   20.090 ±  1.184   #/op
HashWalkBench.walk:cycles                 1048576  avgt    3   75.230 ± 11.333   #/op
HashWalkBench.walk:instructions           1048576  avgt    3   90.075 ± 10.484   #/op# Parallel
HashWalkBench.walk                        1048576  avgt   15    0.024 ±  0.001  us/op
HashWalkBench.walk:L1-dcache-load-misses  1048576  avgt    3    1.156 ±  0.360   #/op
HashWalkBench.walk:L1-dcache-loads        1048576  avgt    3   25.417 ±  1.711   #/op
HashWalkBench.walk:L1-dcache-stores       1048576  avgt    3   23.265 ±  3.552   #/op
HashWalkBench.walk:cycles                 1048576  avgt    3   97.435 ± 69.688   #/op
HashWalkBench.walk:instructions           1048576  avgt    3  102.477 ± 12.689   #/op

由上述执行结果可知,并行执行相同数量的加载(得益于编码的卡表指针),并进行 3 次额外的存储,这需要大约 22 个额外的周期和 12 条指令。此增加似乎对应于此特定工作负载中的三个写入屏障。请注意,L1 缓存未命中率也略高:因为卡标记存储会污染它,从而降低应用程序的有效缓存容量。

总结

GC 通常带有一组屏障,即使没有实际的 GC 工作发生,这些屏障也会影响应用程序的性能。即使是在非常基本的代际收集器(如 Serial/Parallel)的情况下,您也至少有一个引用存储屏障,必须记录代际屏障。更高级的收集器(如 G1)甚至有更复杂的屏障,可以跟踪区域之间的引用。在某些情况下,这种成本是不可接受的,以至于需要一些技巧来避免它,包括无操作 GC,如 Epsilon。

http://www.cadmedia.cn/news/14569.html

相关文章:

  • 苏州专业做网站的公司哪家好最好用的搜索引擎
  • 广安市网站建设哪个模板建站好
  • 邗江区建设局网站常州百度推广代理公司
  • 百度建设公司网站信息流广告是什么意思
  • wordpress.cn淘宝客seo推广教程
  • 常州网站建设流程湖南网站建设推荐
  • 威海外贸网站建设联系方式外贸推广平台哪个好
  • 济南中风险地区巩义关键词优化推广
  • 企业年报汕头自动seo
  • 阿里妈妈通过审核 又拒绝 网站建设不完整淘宝关键词热度查询工具
  • 巴中建设厅网站电话淘宝排名查询
  • 有域名怎么建设网站广州seo全网营销
  • 榆林网站建设电话北京百度推广官网首页
  • 驰业传媒网站建设网站推荐
  • 成都网站建设企业 排名郑州百度推广代运营
  • 技术支持 东莞网站建设 轴承东莞seo快速排名
  • 如何建立公司企业网站长沙网站优化
  • 电商型企业网站建设查询关键词排名软件
  • 现在做跨境电商平台有哪些东莞seo收费
  • 手机网站建设的方法包头seo
  • 杭州网站建设培训班搜狗整站优化
  • 网站seo快排软件怎样找推广平台
  • wordpress去掉作者关键词优化推广排名多少钱
  • tk域名官方网站搜狗优化排名
  • 世界三大咨询公司简单网站建设优化推广
  • 宝安做网站的seo建站要求
  • 企业官网模板站专业关键词排名优化软件
  • 湖北网站开发公司百度搜索网址
  • 成都餐饮小程序开发南昌seo搜索优化
  • 十堰吉安营销型网站优化营销企业网站建设报价