js map方法详解
如何系统的学习JAVA?
如何系统的学习JAVA?
java的整体生态和积累实在是太大了。95年至今20多年的积累,几乎涉及到计算机软硬件的方方面面。我暂且就认为,提主所说的精通,是指jdk本身和一些必要的数据结构以及常用框架和面向对象的基本思想吧。
从11年初至今,一直在学习java相关的知识。其中也走了不少弯路。按自己的积累,给出提主一个自认为合理且有一定深度的学习路线。大致分下面几个阶段吧。
1.首先应尽可能的打牢基础的数据结构和简单的算法基础。
可以去快速的学习一些简单的小型系统,来满足软件学习的兴趣和初期成就感。但,一定要回过头,仔细的巩固数据结构基础和简单算法。类似于这种书就可以。
2.熟练使用Java类库和java第三方工具框架。
学习使用java的语法,尝试理解Java语法设计的逻辑。熟练掌握jdk类库本身,以及各种第三方类库工具包和第三方框架的简单使用。这里学习的同时,推荐看看《设计模式》,《代码整洁之道》,《spring源码解读》,《Spring揭秘》等这一类的书集。
3.理解学习jdk类库本身的应用源码实现和主流第三方框架的源码和架构设计。
比如jdk本身的数据结构二叉树,红黑树,treemap,以及异步包的unsafe,同步阻塞队列,call-future等等包源码,以及线程基础类的实现,各个类库设计的结构和设计模式。吃透第三方框架的设计思想,理解学习第三方框架的核心源码。
当然,这里面可能会涉及到其他的事务,分布式协议等,这里不再展开。这个过程并非一朝一夕,可能需要大量的时间和技术感悟。当然,《设计模式》,《代码整洁之道》,《spring源码解读与设计详析》,《Spring揭秘》等等这一大类书,在这个过程可以理解大差不差了。
4.理解jdk,jre即jvm原理和实现。
这里我推荐看下葛老师的《实战java虚拟机》,里面讲解比较偏实操。容易上手理解。
首先,可以从jdk自带的工具学习来入手。
比如:jstat,jmap,jstack,jps,jdb.......甚至还有直接可以窥视运行期间实际内存数据的HSDB。当然,作为学习初步,我们只需要理解常用的几个命令,并知道其代表的意义即可。毕竟,第三方监控工具,包括jdk本身也提供了3个可视化的监控。
其次,理解jvm的运行加载原理,搞懂class文件结构。
这个过程我们可以借助之前会用的监控工具,理解jvm加载的基本原理。可以参考官方各个版本的jvm标准,学习看懂class文件。在此基础上可以使用如classpy等工具,方便我们直接阅读class文件。也可以试试支持class字节码级别的单步调试工具。甚至,可以尝试用用jvm汇编编码工具。
接下来,理解jvm的垃圾回收机制发展历史和各个主流垃圾回收器的工作原理。
这个过程其实非常复杂。垃圾回收器有各种串行,并行,新声代/swap和老年代,以及回收警戒线,full触发条件,各种个样的基本参数和不怎么用的超参数,以及G1的H区,ZGC等等。。。还好的是,GC并不属于jvm官方规范的一部分。
然后,动手做一些jvm的实践和实战,
比如,jvm常见的故障排查和故障总结,性能调优,热加载,class字节码的动态操作,asm等。
最后,可以尝试实现自己的jvm。(当然这个步骤,对很多同学来说不是必须了)
这里我推荐几本书,也是彻底搞懂jvm规范的学习路径。最好自己实现垃圾回收器。
周老师的《深入理解Java虚拟机》。
接下来是《深入嵌入式java虚拟机》和配套源码。这个cldc的jvm源码只有1M多。目前在oracle的官网上,仍然可以下载。是一个设计非常精简的jvm实现。
接下来,可以去阅读《自己动手写java 虚拟机》。这本书的jvm实现是采用go语言编写。当然其中也有很多设计并不是非常合理。但基本都遵循了jvm规范。
这个时候就可以去看看github上各种jvm的开源实现了。有go,scalajvm,javainjava,ajvm,python-jvm,lua,各个版本各个不同的jvm实现。
当然,这些实现都只是基本原理。
后面推荐你去看《实战hotspot》豹子书,关注高级语言虚拟机的圈子。
当然,垃圾回收的书籍比较少,这里还是推荐给你垃圾回收的经典书《The Garbage Collection Cookbook》。实际上对新的垃圾回收算法有兴趣,可以去知乎搜索相关的论文和GC算法开源实现的demo。
5.当然,我的建议只是针对Java本身。
真正要达到完全学好java生态,软件工程,计算机网络,大数据基础知识,mahuot,sparklib,分布式搜索架构,各种消息中间件,缓存中间件,数据库,DNS/CDN。。。。。这些都是做互联网应用,避无可避的。
只能建议,通用知识熟练,钻研方向精通,相关生态了解。
由于提问是针对java本身。我就不再展开说其他具体方向了。描述的是大的技术方向,并没有其他答主那样,具体去讨论语法糖这种级别。希望对提主有所帮助。
有任何问题,欢迎关注回复,与我讨论。谢谢。
如何正确学会Java虚拟机调优?
一点小经验仅供参考:
1) 堆
运行时数据区域,所有类实例和数组的内存均从此处分配。Java 虚拟机启动时创建。对象的堆内存由称为垃圾回收器 的自动内存管理系统回收。
堆由两部分组成:
其中eden fromspace tospace也叫年轻代(young),old space叫旧生代.
其中还有S1,S0(在JDK的自带工具输出中会看到),分别指的是Survivor space,存放每次垃圾回收后存活的对象.
Old Generation , 主要存放应用程序中生命周期长的存活对象
垃圾回收主要是对Young Generation块和Old Generation块内存进行回收,YG用来放新产生的对象,经过几次回收还没回收掉的对象往OG中移动,
对YG进行垃圾回收又叫做MinorGC,对OG垃圾回收叫MajorGC,两块内存回收互不干涉
2) 非堆内存
JVM具有一个由所有线程共享的方法区。方法区属于非堆内存。它存储每个类结构,如运行时常数池、字段和方法数据,以及方法和构造方法的代码。它是在 Java 虚拟机启动时创建的。
除了方法区外,Java 虚拟机实现可能需要用于内部处理或优化的内存,这种内存也是非堆内存。 例如,JIT 编译器需要内存来存储从 Java 虚拟机代码转换而来的本机代码,从而获得高性能。
Permanent Generation (图中的Permanent Space) 存放JVM自己的反射对象,比如类对象和方法对象
3) 回收算法和过程
JVM采用一种分代回收 (generational collection) 的策略,用较高的频率对年轻的对象(young generation)进行扫描和回收,这种叫做minor collection,而对老对象(old generation)的检查回收频率要低很多,称为major collection。这样就不需要每次GC都将内存中所有对象都检查一遍。
当一个URL被访问时,内存申请过程 如下:
A. JVM会试图为相关Java对象在Eden中初始化一块内存区域
B. 当Eden空间足够时,内存申请结束。否则到下一步
C. JVM试图释放在Eden中所有不活跃的对象(这属于1或更高级的垃圾回收), 释放后若Eden空间仍然不足以放入新对象,则试图将部分Eden中活跃对象放入Survivor区
D. Survivor区被用来作为Eden及OLD的中间交换区域,当OLD区空间足够时,Survivor区的对象会被移到Old区,否则会被保留在Survivor区
E. 当OLD区空间不够时,JVM会在OLD区进行完全的垃圾收集(0级)
F. 完全垃圾收集后,若Survivor及OLD区仍然无法存放从Eden复制过来的部分对象,导致JVM无法在Eden区为新对象创建内存区域,则出现”out of memory错误”
对象衰老的过程
young generation的内存,由一块Eden(伊甸园,有意思)和两块Survivor Space(1.4文档中称为semi-space)构成。新创建的对象的内存都分配自eden。两块Survivor Space总有会一块是空闲的,用作copying collection的目标空间。Minor collection的过程就是将eden和在用survivor space中的活对象copy到空闲survivor space中。所谓survivor,也就是大部分对象在伊甸园出生后,根本活不过一次GC。对象在young generation里经历了一定次数的minor collection后,年纪大了,就会被移到old generation中,称为tenuring。(是否仅当survivor space不足的时候才会将老对象tenuring? 目前资料中没有找到描述)
剩余内存空间不足会触发GC,如eden空间不够了就要进行minor collection,old generation空间不够要进行major collection,permanent generation空间不足会引发full GC。
4 接下来这部分讲解的是TOMCAT或者其他服务器出现如下错误时的分析:
1、首先是: Java heap space
解释:
Heap size 设置
JVM堆的设置是指java程序运行过程中JVM可以调配使用的内存空间的设置.JVM在启动的时候会自动设置Heap size的值,其初始空间(即-Xms)是物理内存的1/64,最大空间(-Xmx)是物理内存的1/4。可以利用JVM提供的-Xmn -Xms -Xmx等选项可进行设置。Heap size 的大小是Young Generation 和Tenured Generaion 之和。
提示:在JVM中如果98%的时间是用于GC且可用的Heap size 不足2%的时候将抛出此异常信息。
提示:Heap Size 最大不要超过可用物理内存的80%,一般的要将-Xms和-Xmx选项设置为相同,而-Xmn为1/4的-Xmx值。
解决方法:
手动设置Heap size
修改TOMCAT_,在“echo Using CATALINA_BASE: $CATALINA_BASE”上面加入以下行:
Java代码
set JAVA_OPTS%JAVA_OPTS% -server -Xms800m -Xmx800m -XX:MaxNewSize256m
set JAVA_OPTS%JAVA_OPTS% -server -Xms800m -Xmx800m -XX:MaxNewSize256m
或修改
在“echo Using CATALINA_BASE: $CATALINA_BASE”上面加入以下行:
JAVA_OPTS$JAVA_OPTS -server -Xms800m -Xmx800m -XX:MaxNewSize256m
2、其次是: PermGen space
原因:
PermGen space的全称是Permanent Generation space,是指内存的永久保存区域,这块内存主要是被JVM存放Class和Meta信息的,Class在被Loader时就会被放到PermGen space中,它和存放类实例(Instance)的Heap区域不同,GC(Garbage Collection)不会在主程序运行期对PermGen space进行清理,所以如果你的应用中有很CLASS的话,就很可能出现PermGen space错误,这种错误常见在web服务器对JSP进行pre compile的时候。如果你的WEB APP下都用了大量的第三方jar, 其大小超过了jvm默认的大小(4M)那么就会产生此错误信息了。
解决方法:
1. 手动设置MaxPermSize大小
修改TOMCAT_(Linux下为),在Java代码
“echo Using CATALINA_BASE: $CATALINA_BASE”上面加入以下行:
set JAVA_OPTS%JAVA_OPTS% -server -XX:PermSize128M -XX:MaxPermSize512m
“echo Using CATALINA_BASE: $CATALINA_BASE”上面加入以下行:
set JAVA_OPTS%JAVA_OPTS% -server -XX:PermSize128M -XX:MaxPermSize512m
下为:
Java代码
JAVA_OPTS$JAVA_OPTS -server -XX:PermSize128M -XX:MaxPermSize512m
JAVA_OPTS$JAVA_OPTS -server -XX:PermSize128M -XX:MaxPermSize512m
JVM的默认设置
堆 (heap)(News Generation 和Old Generaion 之和)的设置
初始分配的内存由-Xms指定,默认是物理内存的1/64但小于1G。
最大分配的内存由-Xmx指定,默认是物理内存的1/4但小于1G。
默认空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制,可以由-XX:MinHeapFreeRatio指定。
默认空余堆内存大于70%时,JVM会减少堆直到-Xms的最小限制,可以由-XX:MaxHeapFreeRatio指定。
服务器一般设置-Xms、-Xmx相等以避免在每次GC 后调整堆的大小,所以上面的两个参数没啥用。
-Xmn 设置young generation的heap大小
-XX:MinHeapFreeRatio与-XX:MaxHeapFreeRatio设定空闲内存占总内存的比例范围,这两个参数会影响GC的频率和单次GC的耗时。-XX:NewRatio决定young与old generation的比例。Young generation空间越大,minor collection频率越低,但是old generation空间小了,又可能导致major collection频率增加。-XX:NewSize和-XX:MaxNewSize直接指定了young generation的缺省大小和最大大小。
非堆内存 的设置
默认分配为64M
-XX:PermSize设置最小分配空间,-XX:MaxPermSize设置最大分配空间。一般把这两个数值设为相同,以减少申请内存空间的时间。
再讲解和笔记下,JDK下的一些相关看内存管理工具的使用:
查看jvm内存状态:
jstat -gcutil pid 1000 20
异常情况的例子
jstat -gcutil pid 1000 20
S0 S1 E O P YGC YGCT FGC FGCT GCT
0.00 0.00 99.99 82.51 53.11 2409 1.205 10117 7250.393 7251.598
0.00 0.00 83.42 82.55 53.10 2409 1.205 10118 7252.650 7253.855
0.00 0.00 56.06 82.46 53.10 2410 1.205 10120 7254.467 7255.672
0.00 0.00 32.11 82.55 53.10 2411 1.205 10121 7256.673 7257.877
0.00 0.00 99.99 82.55 53.10 2412 1.205 10123 7257.026 7258.231
0.00 0.00 76.00 82.50 53.10 2412 1.205 10124 7259.241 7260.446
这个数据显示Full GC频繁发生。
正常情况的例子
S0 S1 E O P YGC YGCT FGC FGCT GCT
0.00 0.00 0.24 55.39 99.60 171 0.667 1339 393.364 394.031
0.00 0.00 0.24 55.39 99.60 171 0.667 1339 393.364 394.031
0.00 0.00 0.24 55.39 99.60 171 0.667 1339 393.364 394.031
0.00 0.00 0.24 55.39 99.60 171 0.667 1339 393.364 394.031
0.00 0.00 0.24 55.39 99.60 171 0.667 1339 393.364 394.031
0.00 0.00 0.24 55.39 99.60 171 0.667 1339 393.364 394.031
参数含义:
S0:Heap上的 Survivor space 0 段已使用空间的百分比
S1:Heap上的 Survivor space 1 段已使用空间的百分比
E: Heap上的 Eden space 段已使用空间的百分比
O: Heap上的 Old space 段已使用空间的百分比
P: Perm space 已使用空间的百分比
YGC:从程序启动到采样时发生Young GC的次数
YGCT:Young GC所用的时间(单位秒)
FGC:从程序启动到采样时发生Full GC的次数
FGCT:Full GC所用的时间(单位秒)
GCT:用于垃圾回收的总时间(单位秒)
2 Dump出内存
2.1 找出要dump的线程pid
在Linux下,使用ps –aux
2.2 Dump出内存使用详情
可以通过命令:
jmap -dump:filea.hprof pid
例如:jmap -heap 2343,可以看到
Attaching to process ID 2343, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 11.0-b16
using thread-local object allocation.
Parallel GC with 8 thread(s)
Heap Configuration:
MinHeapFreeRatio 40
MaxHeapFreeRatio 70
MaxHeapSize 4294967296 (4096.0MB)
NewSize 2686976 (2.5625MB)
MaxNewSize -65536 (-0.0625MB)
OldSize 5439488 (5.1875MB)
NewRatio 2 (YG,OG 大小比为1:2)
SurvivorRatio 8
PermSize 21757952 (20.75MB)
MaxPermSize 268435456 (256.0MB)
Heap Usage:
PS Young Generation
Eden Space:
capacity 1260060672 (1201.6875MB)
used 64868288 (61.86322021484375MB)
free 1195192384 (1139.8242797851562MB)
5.148028935546367% used
From Space:
capacity 85524480 (81.5625MB)
used 59457648 (56.70323181152344MB)
free 26066832 (24.859268188476562MB)
69.52120375359195% used
To Space:
capacity 85852160 (81.875MB)
used 0 (0.0MB)
free 85852160 (81.875MB)
0.0% used
~~~~~~~~~~~~~~~~~~~~~~~~~~这三块为上面所说的YG大小和使用情况
PS Old Generation
capacity 2291138560 (2185.0MB)
used 1747845928 (1666.8757705688477MB)
free 543292632 (518.1242294311523MB)
76.28722062099989% used
~~~~~~~~~~~~~~~~~~~~~~~~~~OG大小和使用情况
PS Perm Generation
capacity 108265472 (103.25MB)
used 107650712 (102.6637191772461MB)
free 614760 (0.5862808227539062MB)
99.43217353728436% used
jstat
jstat是vm的状态监控工具,监控的内容有类加载、运行时编译及GC。
使用时,需加上查看进程的进程id,和所选参数。以下详细介绍各个参数的意义。
jstat -class pid:显示加载class的数量,及所占空间等信息。
jstat -compiler pid:显示VM实时编译的数量等信息。
jstat -gc pid:可以显示gc的信息,查看gc的次数,及时间。其中最后五项,分别是young gc的次数,young gc的时间,full gc的次数,full gc的时间,gc的总时间。
jstat -gccapacity:可以显示,VM内存中三代(young,old,perm)对象的使用和占用大小,如:PGCMN显示的是最小perm的内存使用量,PGCMX显示的是perm的内存最大使用量,PGC是当前新生成的perm内存占用量,PC是但前perm内存占用量。其他的可以根据这个类推, OC是old内纯的占用量。
jstat -gcnew pid:new对象的信息。
jstat -gcnewcapacity pid:new对象的信息及其占用量。
jstat -gcold pid:old对象的信息。
jstat -gcoldcapacity pid:old对象的信息及其占用量。
jstat -gcpermcapacity pid: perm对象的信息及其占用量。
jstat -util pid:统计gc信息统计。
jstat -printcompilation pid:当前VM执行的信息。
除了以上一个参数外,还可以同时加上 两个数字,如:jstat -printcompilation 3024 250 6是每250毫秒打印一次,一共打印6次,还可以加上-h3每三行显示一下标题。
例子:
jstat -gcutil pid 1000 20
S0 S1 E O P YGC YGCT FGC FGCT GCT
47.49 0.00 64.82 46.08 47.69 20822 2058.631 68 22.734 2081.365
0.00 37.91 38.57 46.13 47.69 20823 2058.691 68 22.734 2081.425 这里发生了一次YG GC,也就是MinorGC,耗时0.06s
46.69 0.00 15.19 46.18 47.69 20824 2058.776 68 22.734 2081.510
46.69 0.00 74.59 46.18 47.69 20824 2058.776 68 22.734 2081.510
0.00 40.29 19.95 46.24 47.69 20825 2058.848 68 22.734 2081.582
MajorGC平均时间:22.734/680.334秒
MinorGC平均时间:2058.691/208230.099秒