求文!!!在别的我在什么地方看到什么的,大概是这样:

主题:阿豆的文在LJJ好红啊3万字嘚文就那么多的积分!!!!仰望之,有人知道阿豆的文是什么过人之处这么红吗我看过她的一篇《重生》,看完没啥感觉啊诚心求指教,拜~[61]

阿豆的文在LJJ好红啊3万字的文就那么多的积分!!!!仰望之,有人知道阿豆的文是什么过人之处这么红吗我看过她的一篇《偅生》,看完没啥感觉啊诚心求指教,拜~

情况是这样的:我和她是初中同學上高中后就再也没见过,中间偶尔有一次联系(大概一年一两次)上个月

情况是这样的:我和她是初中同学,上高中后就再也没见過中间偶尔有一次联系(大概一年一两次)。上个月联系过一次后发现很聊的来(聊了大概有半个月)我就约她出来玩,她答应了㈣月二十七号从老家过来我们一起去舟山玩了四天,期间我像她表白她没同意也没拒绝各自回去后五月二号晚上她发消息说没想过做我奻朋友。情况大概就这样子了 但是从那天以后她还是每天找我聊天,还说在车站分开那天我感动到她了求大神分析一下她现在到底是個什么心里??

初中同学一旦以后见面聊得来就会很亲密,没压力很有安全感,没理由得很放心你表白她没同意,有两个可能:1她没想过这个问题,也就是没有恋爱冲动2,出于女生的矜持每个人都有过去,有很多故事这些事不好讲,反正很苦涩但是她也没囿拒绝,事后甚至害怕两个人关系远离主动找你聊天,最少最少你在她心里也是最看重的几个朋友之一甚至是最亲近的朋友,说直白點她觉得你很好,很重要
不过,女孩子找男朋友要复杂得多了你很好,但是你阳光快乐吗你睿智成熟可以保护一个家庭吗?衣食住行可以保障吗至少,有个可以遮风挡雨的地方吗说这些,男孩子往往不爱听觉得是对感情的侮辱,可是女孩子对这些实际问题更看重换言之,她们对自己的爱情和人生更加认真
她说你有感动到她,这倒是实话她动心了,你的真诚和人品她很认同只不过她觉嘚还差点东西,她很犹豫或者是差了互相了解,或者是差了其他的不过她至少会放慢脚步等你的表现。换言之你交了订金了,暂时鈈用担心她倾心别人
接下来,最完美的办法就是上文火慢慢来,目的性太强是要炸锅的
跟她多聊聊你这些年的故事吧,多约出来吃吃饭喝喝茶,带她去浪漫的地方让她品味你的人生,让她觉得你的生活方式就是她想要的让她觉得你就是最好的肩膀,最好的减压劑两个人的爱情,两个人享受对自己也未尝不是好事。这个阶段腰包怕是要瘪了 还有,最好不要着急发生关系因为很多时候,有些小缺点在发生关系后会无理由地放大这其实并不利于恋爱。 好啦总结一下:有个机会摆在你面前,要用智慧和魅力抓住我完全有悝由相信一一你能抓住,而且你还会很享受后面的过程

还有,哈哈,我不太放心还要啰嗦几句。其实表白什么的最要不得几句话僦让女孩爱上自己,这很扯完美的表白是什么?一一不表白!咳就是不用嘴巴说,没有说就没有拒绝不容拒绝的表白,才是真表白你约她出来这件事本身就是表白。约她吃饭本身就是表白约她做浪漫的事本身就是表白。直到她很不放心地站在你面前要献出一些很偅要的东西的时候她会问你要你的表白(承诺)。那才是完美的表白是深沉的表白,是一个男人真正的表白


Java作为一种面向对象的跨平台语訁,其对象、内存等一直是比较难的知识点所以,即使是一个Java的初学者也一定或多或少的对JVM有一些了解。可以说关于JVM的相关知识,基本是每个Java开发者必学的知识点也是面试的时候必考的知识点。

在JVM的内存结构中比较常见的两个区域就是堆内存和栈内存(如无特指,本文提到的栈均指的是虚拟机栈)关于堆和栈的区别,很多开发者也是如数家珍有很多书籍,或者网上的文章大概都是这样介绍的:

1、堆是线程共享的内存区域栈是线程独享的内存区域。

2、堆中主要存放对象实例栈中主要存放各种基本数据类型、对象的引用。

但昰作者可以很负责任的告诉大家,以上两个结论均不是完全正确的

在我之前的文章《》中,介绍过了关于堆内存并不是完完全全的线程共享有关的知识点本文就第二个话题来探讨一下。

在《Java虚拟机规范》中关于堆有这样的描述:

在Java虚拟机中,堆是可供各个线程共享嘚运行时内存区域也是供所有类实例和数组对象分配内存的区域。

在《》文章中我们也介绍过,一个Java对象在堆上分配的时候主要是茬Eden区上,如果启动了TLAB的话会优先在TLAB上分配少数情况下也可能会直接分配在老年代中,分配规则并不是百分之百固定的这取决于当前使鼡的是哪一种垃圾收集器,还有虚拟机中与内存有关的参数的设置

但是一般情况下是遵循以下原则的:

  • 对象优先在Eden区分配

    • 优先在Eden分配,洳果Eden没有足够空间会触发一次Monitor GC

    • 需要大量连续内存空间的Java对象,当对象需要的内存大于-XX:PretenureSizeThreshold参数的值时对象会直接在老年代分配内存。

但昰虽然虚拟机规范中是有着这样的要求,但是各个虚拟机厂商在实现虚拟机的时候可能会针对对象的内存分配做一些优化。这其中最典型的就是HotSpot虚拟机中的JIT技术的成熟使得对象在堆上分配内存并不是一定的。

其实在《深入理解Java虚拟机》中作者也提出过类似的观点,洇为JIT技术的成熟使得"对象在堆上分配内存"就不是那么绝对的了但是书中并没有展开介绍到底什么是JIT,也没有介绍JIT优化到底做了什么那麼接下来我们就来深入了解一下:

我们大家都知道,通过 javac 将可以将Java程序源代码编译转换成 java 字节码,JVM 通过解释字节码将其翻译成对应的机器指令逐条读入,逐条解释翻译这就是传统的JVM的解释器(Interpreter)的功能。很显然Java编译器经过解释执行,其执行速度必然会比直接执行可執行的二进制字节码慢很多为了解决这种效率问题,引入了

有了JIT技术之后Java程序还是通过解释器进行解释执行,当JVM发现某个方法或代码塊运行特别频繁的时候就会认为这是“热点代码”(Hot Spot Code)。然后JIT会把部分“热点代码”翻译成本地机器相关的机器码并进行优化,然后再紦翻译后的机器码缓存起来以备下次使用。

上面我们说过要想触发JIT,首先需要识别出热点代码目前主要的热点代码识别方式是热点探测(Hot Spot Detection),HotSpot虚拟机中采用的主要是基于计数器的热点探测

基于计数器的热点探测(Counter Based Hot Spot Detection)采用这种方法的虚拟机会为每个方法,甚至是代码块建立计数器统计方法的执行次数,某个方法超过阀值就认为是热点方法触发JIT编译。

JIT在做了热点检测识别出热点代码后除了会对其字節码进行缓存,还会对代码做各种优化这些优化中,比较重要的几个有:逃逸分析、 锁消除、 锁膨胀、 方法内联、 空值检查消除、 类型檢测消除、 公共子表达式消除等

而这些优化中的逃逸分析就和本文要介绍的内容有关了。

逃逸分析(Escape Analysis)是目前Java虚拟机中比较前沿的优化技术这是一种可以有效减少Java 程序中同步负载和内存堆分配压力的跨函数全局数据流分析算法。通过逃逸分析Hotspot编译器能够分析出一个新的对潒的引用的使用范围从而决定是否要将这个对象分配到堆上。

逃逸分析的基本行为就是分析对象动态作用域:当一个对象在方法中被定义後它可能被外部方法所引用,例如作为调用参数传递到其他地方中称为方法逃逸。

sb是一个方法内部变量上述代码中并没有将他直接返回,这样这个StringBuffer又不会被其他方法所改变这样它的作用域就只是在方法内部。我们就可以说这个变量并没有逃逸到方法外部

有了逃逸汾析,我们可以判断出一个方法中的变量是否有可能被其他线程所访问或者改变那么基于这个特性,JIT就可以做一些优化:

关于同步省略大家可以参考我之前的《》中关于锁消除技术的介绍。本文主要来分析下标量替换和栈上分配

我们说,JIT经过逃逸分析之后如果发现某个对象并没有逃逸到方法体之外的话,就可能对其进行优化而这一优化最大的结果就是可能改变Java对象都是在堆上分配内存的这一原则。

对象要分配在堆上其实有很多原因但是有一点比较关键的和本文有关的,那就是因为堆内存在访问上是线程共享的这样一个线程创建出来的对象,其他线程也能访问到

那么,试想下如果我们在某一个方法体内部创建了一个对象,并且对象并没有逃逸到方法外的话那还有必要一定要把对象分配到堆上吗?

其实就没有必要了因为这个对象并不会被其他线程所访问到,生命周期也只是在一个方法内蔀也就不用大费周折的在堆上分配内存,也减少了内存回收的必要

那么,有了逃逸分析之后发现一个对象并没有逃逸到放法外的话,通过什么办法可以进行优化减少对象在堆上分配可能呢?

这就是栈上分配在HotSopt中,栈上分配并没有正在的进行实现而是通过标量替換来实现的。

所以我们重点介绍下什么是标量替换,如何通过标量替换实现栈上分配

标量(Scalar)是指一个无法再分解成更小的数据的数據。Java中的原始数据类型就是标量相对的,那些还可以分解的数据叫做聚合量(Aggregate)Java中的对象就是聚合量,因为他可以分解成其他聚合量囷标量

在JIT阶段,如果经过逃逸分析发现一个对象不会被外界访问的话,那么经过JIT优化就会把这个对象拆解成若干个其中包含的若干個成员变量来代替。这个过程就是标量替换

以上代码中,point对象并没有逃逸出alloc方法并且point对象是可以拆解成标量的。那么JIT就会不会直接創建Point对象,而是直接使用两个标量int x int y来替代Point对象。

可以看到Point这个聚合量经过逃逸分析后,发现他并没有逃逸就被替换成两个聚合量了。

通过标量替换原本的一个对象,被替换成了多个成员变量而原本需要在堆上分配的内存,也就不再需要了完全可以在本地方法栈Φ完成对成员变量的内存分配。

接下来我们就来通过一个实验来看一下逃逸分析是否可以生效,生效后是否真的会发生栈上分配而栈仩分配又有什么好处呢?

// 为了方便查看堆内存中对象个数线程sleep

其实代码内容很简单,就是使用for循环在代码中创建100万个User对象。

我们在alloc方法中定义了User对象但是并没有在方法外部引用他。也就是说这个对象并不会逃逸到alloc外部。经过JIT的逃逸分析之后就可以对其内存分配进荇优化。

我们指定以下JVM参数并运行:

在程序打印出 cost XX ms 后代码运行结束之前,我们使用jmap命令来查看下当前堆内存中有多少个User对象:

从上面嘚jmap执行结果中我们可以看到,堆中共创建了100万个StackAllocTest

在关闭逃逸分析的情况下(-XX:-DoEscapeAnalysis)虽然在alloc方法中创建的User对象并没有逃逸到方法外部,但是还昰被分配在堆内存中也就说,如果没有JIT编译器优化没有逃逸分析技术,正常情况下就应该是这样的即所有对象都分配到堆内存中。

接下来我们开启逃逸分析,再来执行下以上代码

在程序打印出 cost XX ms 后,代码运行结束之前我们使用jmap命令,来查看下当前堆内存中有多少個User对象:

从以上打印结果中可以发现开启了逃逸分析之后(?XX:+DoEscapeAnalysis),在堆内存中只有8万多个StackAllocTestUser对象也就是说在经过JIT优化之后,堆内存中分配的对象数量从100万降到了8万。

除了以上通过jmap验证对象个数的方法以外读者还可以尝试将堆内存调小,然后执行以上代码根据GC的次数來分析,也能发现开启了逃逸分析之后,在运行期间GC次数会明显减少。正是因为很多堆上分配被优化成了栈上分配所以GC次数有了明顯的减少。

前面的例子中开启逃逸分析之后,对象数目从100万变成了8万但是并不是0,说明JIT优化并不会完完全全的所有情况都进行优化

關于逃逸分析的论文在1999年就已经发表了,但直到JDK 1.6才有实现而且这项技术到如今也并不是十分成熟的。

其根本原因就是无法保证逃逸分析嘚性能消耗一定能高于他的消耗虽然经过逃逸分析可以做标量替换、栈上分配、和锁消除。但是逃逸分析自身也是需要进行一系列复杂嘚分析的这其实也是一个相对耗时的过程。

一个极端的例子就是经过逃逸分析之后,发现没有一个对象是不逃逸的那这个逃逸分析嘚过程就白白浪费掉了。

虽然这项技术并不十分成熟但是他也是即时编译器优化技术中一个十分重要的手段。

正常情况下对象是要在堆上进行内存分配的,但是随着编译器优化技术的成熟虽然虚拟机规范是这样要求的,但是具体实现上还是有些差别的

如HotSpot虚拟机引入叻JIT优化之后,会对对象进行逃逸分析如果发现某一个对象并没有逃逸到方法外部,那么就可能通过标量替换来实现栈上分配而避免堆仩分配内存。

所以对象一定在堆上分配内存,这是不对的

最后,我们留一个思考题我们之前讨论过了TLAB,今天又介绍了栈上分配大镓觉得这两个优化有什么相同点和不同点吗?

关于作者Hollis一个对Coding有着独特追求的人,现任阿里巴巴技术专家个人技术博主,技术文章铨网阅读量数千万《程序员的三门课》联合作者。

开发属于自己的第一款IDEA插件! 深入源码分析Java线程池的实现原理

我要回帖

更多关于 地文景观 的文章

 

随机推荐