1. 程式人生 > >JVM運行時內存組成分為一些線程私

JVM運行時內存組成分為一些線程私

朋友 分配內存 pru meta sem 生命周期 sting 線程 清空

  JVM運行時內存組成分為一些線程私有的,其他的是線程共享的。
  
  線程私有
  
  程序計數器:當前線程所執行的字節碼的行號指示器。
  
  Java虛擬機棧:java方法執行的內存模型,每個方法被執行時都會創建一個棧幀,存儲局部變量表,操作棧,動態鏈接,方法出口等信息。每個線程都有自己獨立的棧空間,線程棧只存儲基本類型和對象地址,方法中局部變量存放在線程空間中。
  
  本地方法棧:Native方法服務,在hotspot虛擬機中和java虛擬機棧合二為一。
  
  線程共享
  
  java堆:存放對象實力,幾乎所有的對象實例及其屬性都在這裏分配內存。此外,jvm在內存新生代eden space中開辟了一塊線程私有的區域,稱作TLAB(Thread Local Allocation Buffer),也是每個線程的緩沖區,默認設定為占用Eden space的1%。在編譯器做逃逸分析的時候,根據分析結果,決定是在棧上還是在堆上分配內存,如果在堆上則再分析是否在TLAB上分配內存。在TLAB上分配由於是線程私有的,因此沒有鎖的開銷,效率較高。

  
  方法區:存儲已經被虛擬機加載的類信息,常量,靜態變量,JIT編譯後的代碼等數據,也稱作永久代。java7已經把字符串常量池移動到堆中,在調用String的intern方法時,如果堆中存在相同的字符串對象,會直接保存對象的引用,不會重新創建對象。
  
  直接內存:NIO,Native函數直接分配的堆外內存。DirectBuffer引用會使用此部分內存。
  
  內存分配過程
  
  編譯器通過逃逸分析,確定對象是在棧上分配還是堆上分配。如果在堆上分配直接進入步驟4。
  
  如果是tlab_top + size <= tlab_end,則在TLAB上直接分配對象並增加tlab_top的值。如果現有TLAB不足存放當前對象則進入步驟3。
  
  重新申請一個TLAB,並再次嘗試存放當前對象,如果放不下,則進入步驟4。
  
  在Eden區加鎖(此區多線程共享),如果eden_top + size <= eden_end,則將對象存放在eden區,增加eden_top的值,如果eden區不足以存放,則進入步驟5。
  
  執行一次YGC。
  
  經過YGC後,如果eden還放不下對象,則直接分配到老年代。
  
  對象訪問
  
  句柄訪問:通過棧本地變量表,找到堆中對象實例指針,根據指針在堆中找到實例數據,在方法區中找到對象類型數據。
  
  直接指針:通過棧本地變量表,找到堆中對象實例指針,對象實例指針中保存對象實例數據,在方法區中找到對象類型數據。
  
  對象創建
  
  對象在eden完成內存分配。
  
  eden滿了,在創建對象,會因為申請不到空間,觸發minor gc,堆eden+s 區進行回收。
  
  進行minor gc時,eden區不能被回收的對象進入s區,另一個s區中不能被gc回收的對象也會進入這個s區,始終保證一個s區空置。
  
  如果s區滿了,這些對象會被copy到old區,或者s區沒有滿,但是有些對象足夠old了,會被放入old區。
  
  old區滿了之後,進行full gc。
  
  內存溢出
  
  在JVM申請內存的過程中,會遇到無法申請到足夠內存的情況,從而導致內存溢出。
  
  虛擬機棧和本地方法區棧溢出:statkoverflowerror:線程請求的棧深度大於虛擬機所允許的最大深度,循環遞歸會觸發這種OOM。outfomemoryerror:虛擬機在擴展棧時無法申請到足夠的內存空間,一般可以通過不停創建線程觸發這種OOM。
  
  java堆溢出:創建大量對象並且對象生命周期很長情況時,會引發outofmemoryerror。
  
  方法區溢出:方法區存放class等元數據信息,如果產生大量的類(如CGLIB),會引發這種內存溢出,outofmemoryerror:permgen space,在使用hibernate等動態生成類框架時會引起這種情況。
  
  protected void Application_Start()
{
// Engine初始化
EngineContext.Initialize(www.078881.cn/ DataSettingsHelper.DatabaseIsInstalled());
// 添加自定義模型綁定
ModelBinders.Binders.Add(www.yongshi123.cn typeof(BaseModel), new AntiquatedModelBinder());
if (DataSettingsHelper.DatabaseIsInstalled(www.yongshiyule178.com))
{
// 清空mvc所有viewengines
ViewEngines.Engines.Clear();
// 註冊自定義mvc viewengines
ViewEngines.Engines.Add(new ThemableRazorViewEngine());
}
// 自定義元數據驗證
ModelMetadataProviders.Current = new AntiquatedMetadataProvider();

AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
DataAnnotationsModelValidatorProvider
.AddImplicitRequiredAttributeForValueTypes = false;
// 註冊模型驗證
ModelValidatorProviders.Providers.Add(
new FluentValidationModelValidatorProvider(new AntiquatedValidatorFactory()));
// 註冊虛擬資源提供程序
var viewResolver = EngineContext.Current.Resolve<IAntiquatedViewResolver>();
var viewProvider = new ViewVirtualPathProvider(www.thd178.com viewResolver.GetEmbeddedViews());
HostingEnvironment.RegisterVirtualPathProvider(viewProvider);
}
復制代碼
我們往往在做系統或者應用框架開發的時候,一般會去找基礎框架給我們提供的合適切入點實現全局初始化。相信玩ASP.NET的朋友應該對Global.asax這個cs文件比較熟悉,或者說他的基類HttpApplication,大概說一下這個HttpApplication對象,HttpApplication的創建和處理時機是在運行時HttpRuntime之後,再往前一點就是IIS服務器容器了,所以HttpApplication就是我們要找的切入點。
EngineContext初看著命名挺唬人的,哈哈,其實還是比較簡單的一個對象,我們暫時管它叫"核心對象上下文"吧,個人的一點小建議,我們在做應用框架的時候,最好能有這麽一個核心對象來管理所有基礎對象的生命周期。先上代碼
復制代碼
/// <summary>
/// 初始化engine核心對象
/// </summary>
/// <returns></returns>
[MethodImpl(MethodImplOptions.Synchronized)]
public static IEngine Initialize(bool databaseIsInstalled)
{
if (Singleton<IEngine>.Instance == null)
{
var config = ConfigurationManager.GetSection("AntiquatedConfig") as AntiquatedConfig;
Singleton<IEngine>.Instance = CreateEngineInstance(config);
Singleton<IEngine>.Instance.Initialize(config,
  
  吞吐量:指的是單位時間內完成的工作量的度量。
  
  響應時間:是提交請求和返回該請求的響應之間使用的時間。
  
  通常平均響應時間越短,系統吞吐量越大,平均響應時間越長,吞吐量越小。
  
  並行垃圾回收器關註的是吞吐量,會在一定程度上犧牲響應時間。可能某次請求會特別慢。
  
  並發垃圾回收器關註的是請求響應時間,會犧牲吞吐量。會盡量使得每次請求時間維持在差不多水平。
  
  對於CMS觸發full gc的情況:
  
  old區使用到一定比例時觸發,通過cmsinitiatingoccupancyfaction來設置。

JVM運行時內存組成分為一些線程私