人人都知道学习的重要性,但是能坚持下来的人寥寥无几,加油。

Algorithm

之前有刷过一阵,但是因为自我放纵,停了快一个月了。这里把之前的刷题记录整理一下。

Reverse Linked ListTwo Sum

作为开始,回顾一下之前的题,下周正式进入状态。🍺。

个人觉得算法相关的问题主要是思维、还有一些套路,每次回头看都会有新的收获,坚持下去就是胜利。

Review

文章来源耗子叔、极客时间左耳听风专栏79讲推荐文章

introduction-to-java-bytecode这篇文章图文并茂地向你讲述了 Java 字节码的一些细节,是一篇很不错的入门文章。

极客时间版权所有: https://time.geekbang.org/column/article/10216

My Way

为什么要了解ta呢?

作者以一次性能优化检测为例子,检测的代码没有通过检入版本控制系统 (checked into a version control)。上线后,本地的改动代码被删除了。过了几个月,想要修改这段代码,但是找不到了(代码是你的财富,保管好ta们)。只能通过反编译获取代码了,但是反编译软件并不是很完美有很多bug。作者基于自己对于字节码文件的了解,选择了直接修改字节码文件来完成任务。

因为JVM的存在,我们学习字节码可以适用于所有Java支持的平台,因为ta的代码的中间表现(an intermediate representationof the code),并不是底层CPU的实际可执行代码。并且Oracle 记录了所有的指令

有一个句子我翻译成了**破釜沉舟**(Desperate times call for desperate measures),不知道合不合适。// TODO 确认

JVM Data Types

祭上一张整理的图片

Java-Data-Types

这还有一个整理的不错的文章JVM数据类型

Stack-Based Architecture

图片来自芋大的知识星球JDK7-JVM内存模型

JDK8中用Metaspace完全替代了 Method Area

本文的作者应该是以JDK7之前的HotSpot为上下文介绍的Runtime Data Area。因为文中方法区的图片, string constants pool还在里面,在《深入理解Java虚拟机》中2.2.5 方法区有这样一句描述:

在目前已经发布的 JDK1.7 的 HotSpot 中,已经把原本放在永久带的字符串常量池移出。

关于方法区,此处让我无限懵逼。

这里通过搜寻各种资料,我要强行给自己定义一波。

方法区是JVM的一种规范,不同版本的虚拟机可以有自己的实现,HotSpot在JDK8以后,将累的元数据放到了本地堆内存(native heap),这块区域叫做metaSpace,它就是方法区的实现。Java8中使用了元空间替代了永久代。$方法区->永久代->Metasapce$不要纠结名字了,都指一个地方。以后就Metaspace了。

元空间使用本地内存,java.lang.OutOfMemoryError: PermGen space这个异常将不复存在取而代之的是java.lang.OutOfMemoryError: Metaspace

不进行扩展了。时刻提醒自己不要被技术诱惑。这会让你陷入深渊,最后从入门到放弃。

这块每次看都有新感受,作为菜鸟的我,每次也是晕晕乎乎的看了一遍又一遍,然后又没有任何印象,我发现文字的记录并不直观,还是需要自己按照程序的执行去走一遍。

java-memory-model

longdouble占用两个本地变量的位置。操作数栈用来记录方法中还行过程中的中间值,或者将参数推送给方法已备调用。

Bytecode Explored

正在执行方法的stack frame中,指令可以将值推送或者弹出operand stack,并将值存储到Local Varialbe Table指定位置中。

使用javap对字节码文件进行解读

1
javap -v xxxx.class

执行的解析:

invoke-sequence

Method Invocations

承接上例,该例中,将计算方法单独抽取,观察方法的调用在字节码文件中的不同表现。

不同于上例的点:

  • $iadd -> invokestatic$
  • 占据3个字节,$ 6->9$,包含了两个额外的字节来构造对调用的方法的引用,
  • 它是calc方法的符号引用,从常量池中解析出来的

此处依然一脸懵逼。翻译出来的话让我升天了。后两点需要特别调查一下。

#2对应常量池中的编号,使用javap -verbose xxxx来查看常量池。缓解了我对第三点的懵逼。

第二点的疑问,为什么要用两个额外的字节?//TODO确认 暂时以规范来理解。留给以后的自己来解决。

第二个例子的执行解析就不画图了,文字解析:

invokestaticstack中创建一个新的帧,然后顺序执行Code下的指令。

iload_0将局部变量表中的第一个int推送到栈顶。

i2d 栈顶的int转化为double

ldc2_wlongdouble型常量值从常量池中推送至栈顶(宽索引)。

invokestatic执行静态方法,返回的值将放到调用者的栈顶。

………,后面的就不解释了,这些我们不必记忆,只需了解即可,真用的时候,能找到它们的翻译字典就行了。

Instance Creations

如题此例我们探寻,类的创建在字节码文件中的表现。

newdupinvokespecial

创建过程解析:

new创建了一个Point,dup复制了一个Pointreference,现在我们有两个Point的引用了。然后将1、2压入栈顶,执行invokespecial,初始化类,对象在heap中分配内存,初始化结束后,操作数栈中的前三位弹出,只剩下最开始new创建的引用了,但是这时Point已经初始化完成了。

invokevirtual根据对象的实际类型进行分配。如果本例中Point有一个子类SpecialPoint,并且重写了方法area,那么就会调用子类中重写的方法。

The Other Way Around

通过字节码指令确定问题,我们不必了解他们的全部调用流程,只需要关注我们的问题点就可以了。

Conclusion

由于字节码指定集的简单性以及在生成指令时几乎没有进行编译器优化,有时候,反汇编类文件来检查代码是一种更好的方法。

耐心很重要,读下来肯定会有收获,可以用翻译,但是一定要🤔。

Tips

最近一周确实工作中没有什么可以算作技术技巧的东西,这里就整理一下之前的一些笔记吧。

Git配置多个SSH-Key

场景有多个git账号时,如公司使用github,自己使用alicode,这是需要配置两个SSH-key。

那么通过在~/.ssh目录下新建config文件来解决。

1
2
3
4
5
6
7
# 配置文件参数
# Host : Host可以看作是一个你要识别的模式,对识别的模式,进行配置对应的的主机名和ssh文件(可以直接填写ip地址)
# HostName : 要登录主机的主机名(建议与Host一致)
# User : 登录名(如gitlab的username)
# IdentityFile : 指明上面User对应的identityFile路径
# Port: 端口号(如果不是默认22号端口则需要指定)
# PreferredAuthentications publickey (固定)

Share

As the beginning,Why I’am here and do the boring job.It’s for life? for my confusion?

Do I like this jop?Sometimes.榨干了我的英文词汇量了,😂。

ARTS对于share的定义:

1
Share:主要是为了建立你的影响力,能够输出价值观。分享一篇有观点和思考的技术文章。

这个其实挺难的,构思文章、落笔、有价值、思考。确实没有什么准备,第一周围绕着这句话展开自己的一些想法谈谈吧,也为以后的Share找准方向。

  1. 输出价值观

每个人的环境大不相同,但是我们会有很多共同的问题,比如: “程序员的中年危机”、“技术是否要转管理”、“新技术的引用”(需要自己和同事的加班,然后公司并不认可)、“跳槽”、“面试准备”(自己准备面试,面试他人)、“选择的艺术-权衡”、“程序员的基本素质”、“工作、学习计划”、哲学、理想、星星月亮等等。

  1. 技术文章

“踩坑记录”、“技术学习”、“技术管理”、“技术选型”等等。

不刻意要求篇幅,但是要求有清晰的提纲,最好有实践有验证过程。一定会存在错误的观点,留给以后的自己或者看到的人来帮忙review,不要陷入无用的争论。

留言

⬆︎TOP