第8章 虚拟机字节码执行系统

6.4字节码指令简介 Java虚拟机的指令由一个字节长度的、代表着某种特定操作含义的数字(称为操作码,Opcode)以及跟随其后的零至多个代表此操作所需参数(称为操作数,Operands)而构成。由于Java虚拟机采用面向操作数栈而不是寄存器的架构,所以大多数的指令都不包含操作数,而只有一个操作码。 6.4.1 字节码与数据类型 Java虚拟机的指令集中,大多数的指令都包含了其操作数所对应的数据类型信息。 如果每一种与数据类型相关的指令都支持Java虚拟机所有运行时数据类型的话,那指令的数量恐怕就会超出一个字节所能表示的数量范围了 前面的被系统吞了 之后再补上 第8章 虚拟机字节码执行系统 8.1概述 8.2 运行时栈帧结构 8.2.1 局部变量表 是一组变量存储空间,用于存放方法参数和方法内部定义的局部变量。 用于存放方法参数和方法内部定义的局部变量。 容量以变量槽(Variable Slot)为最小单位,虚拟机规范中并没有明确指明一个Slot应占用的内存空间大小,知识很有导向性地说道每个Slot都应该能存放一个boolean、byte、char、short、int、float、reference或returnAddress类型的数据。 只要保证计时在64位虚拟机中使用了64位的物理内存空间去实现一个Slot,虚拟机仍要使用对齐和不败的手段让Slot在外观上看起来与32位虚拟机中的一致。 Java中占用32位以内的数据类型有boolean、byte、char、short、int、float、reference和returnAddress8种类型。(Java语言与Java虚拟机种的剧本数据类型是存在本质差别的)。reference类型表示对一个对象实例的引用。虚拟机规范没有指明长度和结构。但需要做到如下两点: 从引用中直接或间接地查找到对象在Java堆中的数据存放的起始地址索引; 引用中直接或简介地查找到对象所属数据类型在方法区中地存储的类型信息,否则无法实现Java语言规范中定义的语法约束。 returnAddress类型目前已经很少见了,为字节码指令jsr、jsr_w和ret服务的,指向一条字节码指令的地址,很古老的Java虚拟机曾经使用这几条指令来实现异常处理,现在已经由异常表替代。 Java中明确的64位的数据类型只有long和double两种。分割存储的做法与“long和double的非原子性协定”类似。 但在局部变量表中不会引起数据安全问题(线程私有)。 索引定位。访问32位数据类型的变量,索引n就代表了使用第n个Slot。64位则会同时使用n和n+1两个Slot。对于两个相邻的共同存放一个64位数据的两个Slot,不允许采用任何方式单独访问其中的某一个。 在方法执行时,如果执行的实例(非static),局部变量表中第0位索引的Slot默认时用于传递方法所属对象实例的引用,在方法中可以通过关键字“this”来访问到这个隐含的参数。 为了尽可能节省栈帧空间,局部变量表中的Slot是可以重用的,方法中定义的变量,其作用域并不一定会覆盖整个方法体。副作用:某些情况下会直接影响到GC。 实例,placeholder能否被回收的根本原因是:局部变量表中的Slot是否还存有关于placeholder数组对象的引用。 局部变量表是GC Roots的一部分。把不用的占用了大量内存的变量手动设置为null值。 但冲编码角度讲,以恰当的变量作用域来控制变量回收时间才是最优雅的解决方法。 ———————————待补充——————————— 局部变量不负初值会编译不通过。

June 8, 2021

第一章 并发编程的挑战

本书特色 结合JDK源码介绍了Java并发框架、线程池的实现原理。 不仅仅局限于Java层面,更深入JVM,CPU。 结合线上应用,给出了一些并发编程实战技巧。 第一章 并发编程的挑战 如果希望通过多线程执行任务让程序运行得更快,会面临非常多得挑战,如上下文切换的问题、死锁的问题,以及受限于硬件和软件的资源限制问题。 1.1 上下文切换 单核处理器支持多线程执行代码,CPU通过给每个线程分配COU时间片来实现。 时间片非常短,所以CPU通过不停的切换线程执行,让我们感觉多个线程是同时执行的,几十毫秒ms。 CPU通过时间片分配算法来循环执行任务。任务从保存到加载的过程就是一次上下文切换。 上下文切换回影响多线程的执行速度。 1.1.1 多线程一定快吗 累加,并发执行的速度比串行慢是因为线程有创建和上下文切换的开销。 1.1.2 测试上下文切换次数和时长 Lmbech3可以测量上下文切换的时长。 cmstat可以测量上下文切换的次数。 CS(Content Switch)表示上下文切换的次数。 1.1.3 如何减少上下文切换 较少上下文切换的方法有无锁并发编程、CAS算法、使用最少线程和使用协程。 无所并发编程:多线程竞争锁时,回引起上下文切换,所以多线程处理数据时,可以用一些办法来避免使用锁,如将数据的ID按照Hash算法取模分段,不同的线程处理不同段的数据。 CAS算法。Java的Atomic包使用CAS算法来更新数据,而不需要加锁。 使用最少线程。避免创建不需要的线程,比如任务很少,但是创建了很多线程来处理,这样回造成大量线程都处于等待状态。 协程:在单线程里实现多任务的调度,并在单线程里维持多个任务间的切换。 1.1.4 减少上下文切换实战 通过见扫线上大量WAITING的线程,来减少上下文切换次数。 1.2 死锁 避免死锁的几个常见方法: 避免一个线程同时获取多个锁。 避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源。 尝试使用定时锁,使用lock.tryLock(timeout)来替代使用内部锁机制。 对于数据库锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的的情况。 1.3 资源限制的挑战 (1)什么是资源限制 资源是指在进行并发编程时,程序的执行速度受限于计算机硬件资源或软件资源。 硬件资源限制:带宽的上传/下载速读、硬盘读写速度和CPU的处理速度。 软件资源限制:数据库的连接数和scoket连接数。 (2)资源限制引发的问题 在并发编程中,将代码执行速度加快的原则是将代码中串行执行的部分变成并发执行,但是如果将某段串行的代码并发执行,因为受限于资源,仍然在串行执行,这时候程序不仅不会加快执行,反而会更慢,因为增加了上下文切换和资源调度的问题。 (3)如何解决资源限制的问题 对于硬件资源限制,可以考虑使用集群并行执行程序。既然单机的资源有限制,那么就让程序在多级上运行。比如使用ODPS、Hadoop或者自己搭建服务器集群,不同的机器吹不同的数据。可以通过“数据ID%机器数”,计算得到一个机器编号,然后由对应编号的机器处理这笔数据。 对于软件资源限制,可以考虑使用资源池将资源复用。比如使用连接池将数据库和Socket连接复用,或者调用对方webservice接口获取数据时,只建立一个连接。 (4)在资源限制情况下进行并发编程 如何在资源限制的情况下,让程序执行得更快呢?方法就是,根据不同得资源限制调整程序得并发度。 1.4 本章小结 本章介绍了在进行并发编程时会遇到的几个挑战,并给出了一些建议。 第二章 Java并发机制的底层实现原理 JVM执行字节码,最终需要转化为汇编指令在CPU上执行,Java中所使用得并发机制依赖于JVM得实现和CPU的指令。 2.1 volatile的应用 1.volatile的定义与实现原理 volatile是轻量级的synchronized,在多处理器开发中保证了共享变量的“可见性”。使用得当的话,比synchronized的使用和执行成本更低,因为它不会引起线程上下文的切换和调度。本文分析Intel处理器是如何实现volatile的。 CPU的术语定义: 术语 英文单词 术语描述 内存屏障 memory barriers 是一组处理器指令,用于事项对内存操作的顺序限制 缓冲行 cache line 缓存中可以分配的最小存储单位。处理器填写缓存线时会加载整个缓存线,需要使用多个主内存读周期 原子操作 atomic line 不可终端的一个或一系列操作 缓存行填充 cache line fill 当处理器试别到内存中读取操作数时可缓存的,处理器读取整个缓存行到适当的缓存(L1,L2,L3的或所有) 缓存命中 cache hit 如果进行高速缓存行填充操作的内存位置仍然是下次处理器访问的地址时,处理器从缓存中读取操作数,而不是从内存读取 写命中 write hit 当处理器将操作数写回到一个内存缓存的区域时,它首先回检查这个缓存的内存地址是否在缓存行中,如果存在一个有效的缓存行,则处理器将这个操作数写回到缓存,而不是写回到内存,这个操作被称为写命中 写缺失 write misses the cache 一个有效的缓存行被写入到不存在的内存区域 为了提高处理速度,处理器不直接个内存进行通信,二十先将系统内存的数据督导内部缓存(L1,L2或其他)后再进行操作,但操作完不知道何时会写到内存。如果对声明了volatile的变量进行写操作,JVM就会像处理器发送一条Lock前缀的指令,将这个变量所在缓存的数据写回到系统内存。但是就算写回到内存,如过其他处理器缓存的值还是旧的,再执行计算操作就会有问题。所以,再多处理器下,未了保证各个处理器缓存的值还是旧的,再执行计算操作就会有问题。所以,在多处理器下,为了保证各个处理器的换粗你一直,就会实现缓存一致性协议,每个处理器通过嗅探在总线上传播的数据来检查自己缓存的值是不是过期了,当处理器发现自己缓存行对应的内存地址被修改,就会将当前处理器的缓存行设置成无效状态,当处理器对这个数据进行修改操作的时候,回重新从系统内存中把数据读到处理器缓存里。 Lock前缀的指令在多核处理器下会引发两件事情: 将当前处理器缓存行的数据写回到系统内存 这个写回内存的操作会使在其他CPU里缓存了该内存地址的数据无效 volatile的两条实现原则:...

June 8, 2021

lantern 邀请码

lantern 是一款专业的代理软件,方便更好的使用互联网,输入我的邀请码 46KBX2 来获得三个月的蓝灯专业版!立即下载 https://github.com/getlantern/forum

June 8, 2021

idea 付费版和免费版的区别

idea 付费版和免费版的区别 IntelliJ IDEA Ultimate IntelliJ IDEA Community Edition Java, Kotlin, Groovy, Scala + + Android + + Maven, Gradle, sbt + + Git, SVN, Mercurial + + Debugger + + Profiling tools + - Spring, Java EE, Micronaut, Quarkus, Helidon, and more + - Swagger, Open API Specifications + - JavaScript, TypeScript + - Database Tools, SQL + -

September 24, 2020

github 的 master 分支将更改为 main

从今年 10 月 1 日起,GitHub 在该平台上创建的所有新的源代码仓库将默认被命名为 “main”,而不是原先的"master"。值得注意的是,现有的存储库不会受到此更改影响。 早在今年 6 月份,受美国大规模的 “Black Lives Matter”运动影响,为了安抚愈演愈烈的民众情绪,GitHub 就宣布将替换掉 master 等术语,以避免联想奴隶制。现如今,在外界一些声音的催促下,这一举措则终于要正式落地了。 除 GitHub 外,为了避免带有所谓的“种族歧视色彩”,许多科技巨头或知名软件也都调整了自己的业务和产品,以平息社会舆论。包括有:MySQL 宣布删除 master、黑名单白名单等术语;Linus Torvalds 通过了 Linux 中避免 master/slave 等术语的提案;还有 Twitter 、GitHub、微软、LinkedIn、Ansible、Splunk、OpenZFS、OpenSSL、JP Morgan、 Android 移动操作系统、Go 编程语言、PHPUnit 和 Curl 等宣布要对此类术语进行删除或更改。同时,IBM、亚马逊、微软也都接连调整面部识别平台业务,以防加深歧视或遭受指责。 且最初在 Git 中写下“master”一词的开发者 Petr Baudis 也于 6 月份在社交网站上表明立场称,自己当年不该使用“master”这个可能给别人造成伤害的词语。并表示,他曾多次希望可以将“master”改成“main”(和“upstream”)。不过直到现在,才由 GitHub 开始主导替换工作。 而对于为何选择“main”而不是其他替换词汇,Github 方面给出的解释为,main 是他们在平台上看到的最受欢迎的 master 替代品。并且 main 这个词汇很短,可以帮助用户形成良好的肌肉记忆;在很多种语言中翻译起来也都很容易。 此外,Github 还透露,截至今年年底,他们将使现有存储库无缝重命名其默认分支。当用户重命名分支机构时,他们将重新定位打开的 PR 和草稿版本、移动分支机构保护策略等,且所有的这些都将自动完成。 事实上,计算机术语政治正确性早已不是新鲜话题。2004 年,“master/slave”曾被全球语言检测机构评为年度最不政治正确的十大词汇之一,时任主席称这是政治渗透到计算机技术控制中的表现。2008 年,开源软件 Drupal 在社区发布消息,高调站队,将“master/slave”重命名为“client/server”。2018年,IETF 也在草案当中指出,要求开源软件更改“master/slave”和“blacklist/whitelist”两项表述。 但是值得思考的是,在计算机源码领域中,“master/slave”和“blacklist/whitelist”之类的技术用语有错吗?一味的“一刀切”的话,会不会导致所谓的矫枉过正呢

September 22, 2020

免费的云存储

七牛云存储 提供了每月10G的免费存储,一般的网站已经够用,如果超额了,费用也很低,可以考虑将网站的图片存在七牛,安全可靠。

September 18, 2020

在线交互式学习k8s/docker/linux

katacoda is Interactive Learning and Training Platform for Software Engineers Helping Developers Learn and Companies Increase Adoption 可以交互式的学习各种前沿技术:k8s linux docker 机器学习等

September 17, 2020

vscode 列选择 快捷键

vscode 列选择 快捷键: shift + alt + 鼠标左键

September 14, 2020

frp 使用

frp 是一个可用于内网穿透的高性能的反向代理应用,支持 tcp, udp, http, https 协议。本文简单的介绍frp的配置使用。 实现内网穿需要有一台公网服务器。本文将公网服务器称为服务端,内网服务器称为客户端。需要开启相关的端口。相关端口没开通,访问就会失败。 frp git地址:https://github.com/fatedier/frp 中文文档:https://github.com/fatedier/frp/blob/master/README_zh.md frp下载地址:https://github.com/fatedier/frp/releases 本文使用软件:frp_0.21.0_linux_amd64.tar.gz 本文使用系统:centos7(公网一台,内网一台) 本文使用软件:frp_0.21.0_linux_amd64.tar.gz,frp的客户端和服务端都在同一个包里。 文件说明 frps.ini: 服务端配置文件 frps: 服务端软件 frpc.ini: 客户端配置文件 frpc: 客户端软件 frps.ini配置 [common] bind_port = 7000 # auth token token = Qwert123 dashboard_port = 7500 # dashboard 用户名密码,默认都为 admin dashboard_user = admin dashboard_pwd = Qwert123 vhost_http_port = 7083 开启服务端服务 ./frps -c ./frps.ini 可以用脚本来启动: #!/bin/sh nohup /usr/local/frp/frps -c /usr/local/frp/frps.ini & frpc.ini配置 [common] #服务器ip地址 server_addr = 121.199.2.XXX server_port = 7000 #开放api,提供reload服务 admin_addr = 127.0.0.1 admin_port = 7400 # auth token token = Qwert123 [ssh] type = tcp local_ip = 127.0.0.1 #ssh端口 local_port = 22 remote_port = 1022 可以使用脚本来启动(start.sh) #!/bin/sh sudo nohup /usr/local/frp/frpc -c /usr/local/frp/frpc....

September 8, 2020