jvm_虚拟机参数讲解(三)
生活随笔
收集整理的這篇文章主要介紹了
jvm_虚拟机参数讲解(三)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
關于新生代和老年代怎么劃分的問題,這塊主要是一些配置,剛才我們也說了分析器這一塊
分配了1M的內存大小,
我現在用的是JDK1.8了,它會生成一個文件,1.8分配太小了,他就啟動不了,
因為我是準備分配5M的,虛擬機加載的時候也需要一定的內存JAVA虛擬機提供了參數-Xss來指定線程的最大棧空間,整個參數也直接決定了函數可調用的最大深度.有些時候我們寫一些遞歸循環,然后虛線遞歸總會報一些錯,超過棧的最大深度了,這塊也是很常見的一個事,-Xss 1m
-Xss 5m
調用的最大深度是多大
就是我調用了2萬多次跑異常了,如果我把參數改一下,我改成4
這個深度就有差別了,這就是10萬多了,調用的次數會不斷的增加,根據你深度的配置和堆一樣,方法區也是一塊所有線程共享的內存區域,它用于保存類的類信息,方法區可以保存多少信息,可以對其進行配置,默認情況下是64M,-XX:MaxPermSize默認是64M,如果系統運行時生產大量的類,就需要設置一個相對合適的方法區,避免出現永久區內存溢出的問題.-XX:PermSize=64M, -XX:PermSize=64M一般這個參數也可以配置到你的應用中
直接內存:在NIO的時候,這個配置無所謂,你也可以不配,如果你以后要用原生的NIO的話,那你可以用一用,但是如果你要用Netty這些框架,-XX:MaxDirectMemorgySize這個你可以不用去關注,如果不設置默認的最大值就是堆空間,其實不設置就完事了,這可能是比較找的一個參數了,他們的訪問速度可能會更快一些,直接就訪問原生的堆空間,跳過了JAVA的堆,這些了解即可
咱們工作中很少有這些東西,想想棧的配置什么時候會用到,我現在要執行一個遞歸的操作,什么時候要去調節一下,有沒有想過這個問題,你在寫一些遞歸的應用的時候,比如說你有一個管理機構,或者有一個樹形列表很大的tree,比如你有一個很大的樹形,樹很深,這個時候你就可以用這個方法了,你可能在程序寫的時候,因為樹可能是好多層的,幾千層幾萬層,這個時候你想在JAVA里面寫程序的話,遞歸調多少次是有限制的,不能無限制的遞歸,一般的來講,你去遍歷一棵樹的時候,最起碼有一個閥值判斷,最終如果沒有葉子節點的時候,我就 把這個遞歸給他停掉了,但是如果某一種情況下,我確實有這么長的樹,一次次的去遍歷一下,那這個就沒辦法了,最大的深度的調用一般是做一些算法運算的時候,你們去寫JAVA代碼,你們涉及到這些運算不多,都是一些應用級別的,你真正寫算法的時候,考量調一下這個參數
虛擬機的工作模式早在JAVA1.6的時候,其實有兩個版本的模式,一個版本是client模式,還有一個版本是server模式,我們的JAVA虛擬機早起是有兩個模式的,java -version 命令就可以看到啟動的JAVA虛擬機不說的話就是Server端的模式早起你在運行程序的時候是有-server 和 -client這兩個參數的,client相對于server的模式啟動會比較快,如果你不追求系統的長時間啟用,僅僅是做一些性能上的測試的話,用client的就可以了,server模式啟動的比較慢原因是對其進行復雜的系統信息的收集和使用復雜的的算法對程序進行優化,所以啟動的時候比較耗時,一般我們的生產環境都會使用server模式,長期運行其性能要遠遠的高于client模式.當然JDK1.7之后就沒有client模式了,只有server模式了,所以你現在運行的都是server模式,除非你用JDK1.5,JDK1.6才可能會有,JVM參數詳細的說明,可能我講的沒有特別的詳細,但大概也都說了,里邊還有好多不常用的,關閉GC的,但是你會關閉嗎,如果關閉你還要手動去做,還有好多參數你可以去瀏覽一下,JVM參數說實話還是比較多的,你在真正工作中,實際遇到問題了,再去做這種調優,如果你不關心,其實你學不學無所謂,這塊了解就可以了,如果問你怎么去調優,你根據不同的生產環境,然后去做一些調優才有意義,我也是發到群里
談到垃圾收集(Garbage Collection),簡稱GC,首先你要澄清這個垃圾是什么概念,線程池,連接池大家有沒有一個概念呢,池子就是一個線程池,咱們的JDBC是一個線程池,比如有五個線程池,如果你JAVA的代碼用到了連接了,我就給你放在使用,用完了之后我再給他歸還,池子一般初始化大小有多少個,一般的都用過druid的,阿里巴巴的,連接超時,斷連這一塊,我給你看一段代碼吧,這是我最近遇到的一個問題,這個問題可能我沒太看仔細,我們打開一段代碼,我最近在做rabitmq的時候,在做MQ的時候,發生了一個小問題,就和activemq差不多,rabitmq是短連接短連接是什么概念呢,我去發一條數據的時候,他去get一條connection,如果已經存在就直接去取,如果不存在就直接getConnection(),就再實例化一個,如果我的鏈接為空,或者connection不可用
你看我這里寫的是或者的關系,如果你的這個連接是空的,或者這個連接是不可用的,那我就讓connectionFactory去實例化一個connection
es是我們剛才的ExecutorService,然后我就寫好是10個,我們配置了一堆參數了,配置在哪個路由,內容是什么,是不是持久化,然后把它放到什么樣的隊列,調用發送消息的方法,發送Rabbitmq的集群,總之就是一個MQ的集群,當我們finally的時候,finally和其他的寫的還不一樣,不是關閉連接,無論是在activemq還是rabbitmq的時候,我可以通過一個connection,去創建多個session,很多公司其實底層并沒有研究的這么細,我真正在用的時候會發現一些小問題的,其實消費者倒無所謂了,我之前給你看的實例的時候
關閉connection,session也是通過connection實例化出來的,也會跟著把session也關閉了,就相當于我在調一個connection.close(),先檢查一下他有多少個connection,然后在關閉自己的connection,如果每次想發一些數據的時候,你發送批量數據還好說,如果我們的producer再生產者這一端,一般都是采用短連接的形式,發一條數據關一下連接,這個時候連接不斷的打開和關閉,非常浪費性能,這個我在真正的實驗也測出一些問題,性能并不是那么高,無論什么樣的公司,無論從什么樣的角度去考慮問題,當然這是一個細節的小問題,不是那么大的事情,如果那么耗資源的一個操作的話,我個人覺得是不可取的,當然API說是可以創建多個Session,所以這一塊這個節點斷線了,因為我采用集群的模式,連接這一塊我寫死了,雖然說寫死了,這個連接我可以連三個集群,但是我確實是連接一個host,這個host就是我的VIP,就是虛擬出來的,這個IP會負載均衡后面三個MQ的服務器,它使用HVProxy去做的,咱們就簡單的說一下,如果說三個節點,開始我的程序是連接VIP
我這里可能組成一個集群了,有多個點,比如由三個MQ組成一個集群,然后現在我想做負載均衡的事情,我現在做的負載均衡是什么的負載均衡,是MQ端的負載均衡,也就是我的應用程序Producer這一塊,去發數據的時候,這樣就降低與MQ的壓力了,把連接請求打散,我又多個producer就可以并行的往里傳,并不需要任何的等,這個就需要在中間加一個東西,說白了就是一個負載均衡的概念,其實負載均衡和反向代理是兩個概念,其實真正意義上的負載均衡LVS和H5,而Nginx和hyproxy這種都是貌似負載均衡的反向代理服務器,如果你在這里用LVS的話,生產者連接的肯定是0這個節點,LVS就會改底層的數據包,就會改底層的IP,就相當于給你負載均衡,然后做到了進來的IP地址是0,然后往外推數據的時候就是1,2,3,然后返回數據的時候不是LVS幫你返回的,而是1,2,3直接幫你返回了這才叫真正意義上的負載均衡,就是TCP/IP級別的負載均衡,而你所謂的反向代理,比如說Nginx,比如說HAProxy像這種東西,進來的確實是0,然后在里面配置1,2,3,讓這三個哥們去做負載均衡,我去把請求給你,你呢給我,然后我再去給他,我就相當于一個proxy,所以這個才叫做反向代理,你把請求給我,我把請求通過我的配置,Nginx不是配置有2嗎,負載均衡給2,服務器2處理完成之后就給Nginx,Nginx然后再給producer,這種實際上就是一種代理的角色,其實服務器的壓力完全就在代理服務器上,如果說是做LVS的話,Nginx其實代理其實是最弱的因為Nginx其實是WEB端的服務器,它并不是專門做負載均衡的,它做負載均衡其實就是upstream,加個大括號{},配置三個IP地址,它是通過upstream模塊去實現負載均衡的,Nginx,HAProxy也是通過一個配置項去實現負載均衡的,處理完之后還是會返給我,我的服務器再給前端的client端,它是這樣一個模式,就是關于負載均衡和反向代理的概念,這個你要清楚,面試的時候別人會問你,說負載均衡和反向代理,很多人在學習的時候
我這里三個服務器組成一個集群了cluster,然后我不管你用不用反向代理,其實你真正的Producer生產者,你想給我去發數據,你只能去連集群中的一個節點,這個是毋庸置疑的,跟集群中的某個節點做通信,無論是mysql的主從,現在mysql做集群方案多了去了,包括ORACLE的集群方案,最終Connection連接的時候只連接一個節點,無論什么集群,不可能一個連接走三份,那這些怎么玩,所以說要理解這個事情,那么假設說,在進行連接的時候,我這個集群就直接斷掉了,斷掉了下面的代碼可能就不可用了,因為這個連接已經掛掉了,跑異常的話肯定會走catch,走catch就會取走close,我去把之前的連接去給釋放了,connection.close()之后connection是個什么狀態呢,我調close是一個什么樣的狀態,第一點它不可能馬上響應你的close,它可能會調用close方法,它調用close會占用程序的資源,釋放之后需用使用GC是回收connection之前所擁有的資源,調用這個方法就是想把這個對象清空,如果你這么去寫的話會有一個問題,它并不是馬上把這個connection滯空的,connection為空connection不可用,是不是在打開連接的狀態,這樣我再去創建一個連接,等待這邊慢慢的關閉了,下次GC來的時候去把GC釋放了,這是一個不錯的方案,或者你就暴力一點,close之后就手工的去做這種事情,
手工的去做也不知道是不是馬上就為空了,因為GC的這個事情你不敢保證,GC并不是你代碼寫成null,下一秒就能把你制成空,所以這種可能還是保證的不那么徹底,就算你寫成空,也必須GC才能滯空,很多時候會有這么一個問題,我這個集群萬一中途掛了,那會是一個怎樣的場景以后無論你是寫連接池的時候,你一定要注意這個問題,然后就更進一步的確認了GC并不是做什么事,
rabbitmq的啟動速度超級快,
RabbitMQ沒有監聽的概念,都是短連接,receive的狀態一直在變,每次發一條就斷開一個連接再連,在finally的時候都是connection.close(),連接都是關閉了,因為在接收這段性能都是很高的JVM去GC的,而不是你自己去做的.
?
總結
以上是生活随笔為你收集整理的jvm_虚拟机参数讲解(三)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: jvm_虚拟机参数讲解(二)
- 下一篇: jvm_垃圾收集算法讲解(一)