摘要:源碼版本介紹在分析啟動(dòng)流程時(shí),老是會(huì)碰到各類,這里多帶帶提出來(lái)做下較詳細(xì)的分析。主要由兩部分組成使用指定的回收策略,刪除那些已經(jīng)結(jié)束的所有的生命周期管理就是通過(guò)來(lái)實(shí)現(xiàn)的,其實(shí)該也是依賴了。相關(guān)配置該值表示磁盤占用率達(dá)到該值后會(huì)觸發(fā)。
源碼版本
kubernetes version: v1.3.0
kubelet GC介紹在分析kubelet啟動(dòng)流程時(shí),老是會(huì)碰到各類GC,這里多帶帶提出來(lái)做下較詳細(xì)的分析。
kubelet"s Garbage Collection主要由兩部分組成:
containerGC: 使用指定的container回收策略,刪除那些已經(jīng)結(jié)束的containers
imageManager: k8s所有images的生命周期管理就是通過(guò)imageManager來(lái)實(shí)現(xiàn)的,其實(shí)該imageManager也是依賴了cAdvisor。
imageManager 策略初始化imageManager的回收策略結(jié)構(gòu)如下:
type ImageGCPolicy struct { // Any usage above this threshold will always trigger garbage collection. // This is the highest usage we will allow. HighThresholdPercent int // Any usage below this threshold will never trigger garbage collection. // This is the lowest threshold we will try to garbage collect to. LowThresholdPercent int // Minimum age at which a image can be garbage collected. MinAge time.Duration }
該結(jié)構(gòu)的出廠設(shè)置在cmd/kubelet/app/server.go中的UnsecuredKubeletConfig()接口進(jìn)行。
func UnsecuredKubeletConfig(s *options.KubeletServer) (*KubeletConfig, error) { ... imageGCPolicy := kubelet.ImageGCPolicy{ MinAge: s.ImageMinimumGCAge.Duration, HighThresholdPercent: int(s.ImageGCHighThresholdPercent), LowThresholdPercent: int(s.ImageGCLowThresholdPercent), } ... }
賦值的KubeletServer的幾個(gè)參數(shù)的初始化在cmd/kubelet/app/options/options.go中的NewKubeletServer()接口中進(jìn)行:
func NewKubeletServer() *KubeletServer { return &KubeletServer{ ... ImageMinimumGCAge: unversioned.Duration{Duration: 2 * time.Minute}, ImageGCHighThresholdPercent: 90, ImageGCLowThresholdPercent: 80, ... } }
從上面的初始化過(guò)程可以得出:
在磁盤的占用率高于90%時(shí),imageGC將一直被觸發(fā)
在磁盤的占用率低于80%時(shí),imageGC將不會(huì)觸發(fā)
imageGC會(huì)嘗試先delete最少使用的image,但是如果該image的創(chuàng)建時(shí)間才低于2min,將不會(huì)被刪除。
imageManager初始化上面介紹的都是imageManager的回收策略參數(shù)初始化,下面開始介紹imageManager。
結(jié)構(gòu)所在目錄:pkg/kubelet/image_manager.go
結(jié)構(gòu)如下:
type imageManager interface { // Applies the garbage collection policy. Errors include being unable to free // enough space as per the garbage collection policy. GarbageCollect() error // Start async garbage collection of images. Start() error GetImageList() ([]kubecontainer.Image, error) // TODO(vmarmol): Have this subsume pulls as well. }
可以看到imageManager是個(gè)interface,實(shí)際初始化的結(jié)構(gòu)體是realImageManager:
type realImageManager struct { // Container runtime runtime container.Runtime // Records of images and their use. imageRecords map[string]*imageRecord imageRecordsLock sync.Mutex // The image garbage collection policy in use. policy ImageGCPolicy // cAdvisor instance. cadvisor cadvisor.Interface // Recorder for Kubernetes events. recorder record.EventRecorder // Reference to this node. nodeRef *api.ObjectReference // Track initialization initialized bool }
該接口的初始化需要先回到pkg/kubelet/kubelet.go中的NewMainKubelet()接口中:
func NewMainKubelet( hostname string, nodeName string, ... ) (*Kubelet, error) { ... // setup containerGC containerGC, err := kubecontainer.NewContainerGC(klet.containerRuntime, containerGCPolicy) if err != nil { return nil, err } klet.containerGC = containerGC // setup imageManager imageManager, err := newImageManager(klet.containerRuntime, cadvisorInterface, recorder, nodeRef, imageGCPolicy) if err != nil { return nil, fmt.Errorf("failed to initialize image manager: %v", err) } klet.imageManager = imageManager ... }
可以看到上面的接口中對(duì)containerGC和imageManager都進(jìn)行了初始化,這里先介紹imageManager,containerGC留到下面再講。
newImageManager()接口如下:
func newImageManager(runtime container.Runtime, cadvisorInterface cadvisor.Interface, recorder record.EventRecorder, nodeRef *api.ObjectReference, policy ImageGCPolicy) (imageManager, error) { // 檢查policy參數(shù)有效性 if policy.HighThresholdPercent < 0 || policy.HighThresholdPercent > 100 { return nil, fmt.Errorf("invalid HighThresholdPercent %d, must be in range [0-100]", policy.HighThresholdPercent) } if policy.LowThresholdPercent < 0 || policy.LowThresholdPercent > 100 { return nil, fmt.Errorf("invalid LowThresholdPercent %d, must be in range [0-100]", policy.LowThresholdPercent) } if policy.LowThresholdPercent > policy.HighThresholdPercent { return nil, fmt.Errorf("LowThresholdPercent %d can not be higher than HighThresholdPercent %d", policy.LowThresholdPercent, policy.HighThresholdPercent) } // 初始化realImageManager結(jié)構(gòu) im := &realImageManager{ runtime: runtime, policy: policy, imageRecords: make(map[string]*imageRecord), cadvisor: cadvisorInterface, recorder: recorder, nodeRef: nodeRef, initialized: false, } return im, nil }
查看上面的初始化接口,可以看出該imageManager跟容器runtime、cAdvisor、EventRecorder、nodeRef、Policy都有關(guān)。
這里可以進(jìn)行大膽的猜測(cè):
runtime用于進(jìn)行image的刪除操作
cAdvisor用于獲取image占用磁盤的情況
EventRecorder用于發(fā)送具體的回收事件
Policy就是具體的回收策略了
nodeRef干嘛的?猜不到,還是后面繼續(xù)看源碼吧!
imageManager啟動(dòng)所有的參數(shù)初始化結(jié)束后,需要開始進(jìn)入真正的GC啟動(dòng)流程,該步驟還是需要查看CreateAndInitKubelet()接口。
接口目錄:cmd/kubelet/app/server.go
接口調(diào)用流程:main -> app.Run -> run -> RunKubelet -> CreateAndInitKubelet
接口如下:
func CreateAndInitKubelet(kc *KubeletConfig) (k KubeletBootstrap, pc *config.PodConfig, err error) { ... k.StartGarbageCollection() return k, pc, nil }
該接口調(diào)用了啟動(dòng)GC的接口StartGarbageCollection(),具體實(shí)現(xiàn)如下:
func (kl *Kubelet) StartGarbageCollection() { go wait.Until(func() { if err := kl.containerGC.GarbageCollect(kl.sourcesReady.AllReady()); err != nil { glog.Errorf("Container garbage collection failed: %v", err) } }, ContainerGCPeriod, wait.NeverStop) go wait.Until(func() { if err := kl.imageManager.GarbageCollect(); err != nil { glog.Errorf("Image garbage collection failed: %v", err) } }, ImageGCPeriod, wait.NeverStop) }
上面的接口分別啟動(dòng)了containerGC和imageManager的協(xié)程,可以看出containerGC是每1分鐘觸發(fā)回收,imageManager是每5分鐘觸發(fā)回收。
該GarbageCollect()接口需要根據(jù)之前參數(shù)初始化時(shí)的realImageManager結(jié)構(gòu)進(jìn)行查看,進(jìn)入kl.imageManager.GarbageCollect()一看究竟:
func (im *realImageManager) GarbageCollect() error { // 獲取節(jié)點(diǎn)上所存在的images的磁盤占用率 fsInfo, err := im.cadvisor.ImagesFsInfo() if err != nil { return err } // 容量及可利用的空間 capacity := int64(fsInfo.Capacity) available := int64(fsInfo.Available) if available > capacity { glog.Warningf("available %d is larger than capacity %d", available, capacity) available = capacity } // Check valid capacity. if capacity == 0 { err := fmt.Errorf("invalid capacity %d on device %q at mount point %q", capacity, fsInfo.Device, fsInfo.Mountpoint) im.recorder.Eventf(im.nodeRef, api.EventTypeWarning, container.InvalidDiskCapacity, err.Error()) return err } // 查看images的磁盤占用率是否大于等于HighThresholdPercent usagePercent := 100 - int(available*100/capacity) if usagePercent >= im.policy.HighThresholdPercent { // 嘗試去回收images的占用率到LowThresholdPercent之下 amountToFree := capacity*int64(100-im.policy.LowThresholdPercent)/100 - available glog.Infof("[ImageManager]: Disk usage on %q (%s) is at %d%% which is over the high threshold (%d%%). Trying to free %d bytes", fsInfo.Device, fsInfo.Mountpoint, usagePercent, im.policy.HighThresholdPercent, amountToFree) // 真正的回收接口 freed, err := im.freeSpace(amountToFree, time.Now()) if err != nil { return err } if freed < amountToFree { err := fmt.Errorf("failed to garbage collect required amount of images. Wanted to free %d, but freed %d", amountToFree, freed) im.recorder.Eventf(im.nodeRef, api.EventTypeWarning, container.FreeDiskSpaceFailed, err.Error()) return err · } } return nil }
這里最關(guān)鍵的接口便是im.freeSpace(),該接口才是真正進(jìn)行資源回收的接口。
該接口有兩個(gè)參數(shù):第一個(gè)便是設(shè)置這次打算回收的空間,第二個(gè)是傳入調(diào)用回收接口的當(dāng)前時(shí)間。
具體的回收,我們進(jìn)入接口繼續(xù)細(xì)看:
func (im *realImageManager) freeSpace(bytesToFree int64, freeTime time.Time) (int64, error) { // 用im.runtime遍歷現(xiàn)存的所有的images,并更新im.imageRecords,下面會(huì)用到。 err := im.detectImages(freeTime) if err != nil { return 0, err } // 操作imageRecords的鎖 im.imageRecordsLock.Lock() defer im.imageRecordsLock.Unlock() // 獲取所有的images images := make([]evictionInfo, 0, len(im.imageRecords)) for image, record := range im.imageRecords { images = append(images, evictionInfo{ id: image, imageRecord: *record, }) } sort.Sort(byLastUsedAndDetected(images)) // 下面的循環(huán)將嘗試刪除images,直到滿足需要?jiǎng)h除的空間為止 var lastErr error spaceFreed := int64(0) for _, image := range images { glog.V(5).Infof("Evaluating image ID %s for possible garbage collection", image.id) // Images that are currently in used were given a newer lastUsed. if image.lastUsed.Equal(freeTime) || image.lastUsed.After(freeTime) { glog.V(5).Infof("Image ID %s has lastUsed=%v which is >= freeTime=%v, not eligible for garbage collection", image.id, image.lastUsed, freeTime) break } // Avoid garbage collect the image if the image is not old enough. // In such a case, the image may have just been pulled down, and will be used by a container right away. // 查看該image的空閑時(shí)間是否夠久,不夠久的話將不刪除 // 這個(gè)時(shí)間在GC的策略中有配置 if freeTime.Sub(image.firstDetected) < im.policy.MinAge { glog.V(5).Infof("Image ID %s has age %v which is less than the policy"s minAge of %v, not eligible for garbage collection", image.id, freeTime.Sub(image.firstDetected), im.policy.MinAge) continue } // 調(diào)用runtime(即Docker)的接口刪除指定的image glog.Infof("[ImageManager]: Removing image %q to free %d bytes", image.id, image.size) err := im.runtime.RemoveImage(container.ImageSpec{Image: image.id}) if err != nil { lastErr = err continue } // 將刪除的鏡像從imageRecords中去除,所以前面需要加鎖 delete(im.imageRecords, image.id) // 增加已經(jīng)刪除的image的size spaceFreed += image.size // 如果已經(jīng)刪除的image的大小已經(jīng)滿足要求,則退出回收流程 if spaceFreed >= bytesToFree { break } } return spaceFreed, lastErr }
基本的imageManager模塊流程差不多就這樣了,這里還可以繼續(xù)深入學(xué)習(xí)下cAdvisor和docker runtime的接口實(shí)現(xiàn)。
containerGC 策略初始化containerGC回收策略相關(guān)結(jié)構(gòu)如下:
type ContainerGCPolicy struct { // Minimum age at which a container can be garbage collected, zero for no limit. MinAge time.Duration // Max number of dead containers any single pod (UID, container name) pair is // allowed to have, less than zero for no limit. MaxPerPodContainer int // Max number of total dead containers, less than zero for no limit. MaxContainers int }
該結(jié)構(gòu)的初始化是在cmd/kubelet/app/kubelet.go文件中的CreateAndInitKubelet()接口中進(jìn)行。
調(diào)用流程:main --> app.Run --> RunKubelet --> CreateAndInitKubelet
func CreateAndInitKubelet(kc *KubeletConfig) (k KubeletBootstrap, pc *config.PodConfig, err error) { var kubeClient clientset.Interface if kc.KubeClient != nil { kubeClient = kc.KubeClient // TODO: remove this when we"ve refactored kubelet to only use clientset. } // containerGC的回收策略初始化 gcPolicy := kubecontainer.ContainerGCPolicy{ MinAge: kc.MinimumGCAge, MaxPerPodContainer: kc.MaxPerPodContainerCount, MaxContainers: kc.MaxContainerCount, } ... }
可以看到實(shí)際的參數(shù)來(lái)源于kc結(jié)構(gòu),而該結(jié)構(gòu)的初始化是在cmd/kubelet/app/kubelet.go文件中的UnsecuredKubeletConfig()接口中進(jìn)行。
調(diào)用流程:main --> app.Run --> UnsecuredKubeletConfig
func UnsecuredKubeletConfig(s *options.KubeletServer) (*KubeletConfig, error) { ... MaxContainerCount: int(s.MaxContainerCount), MaxPerPodContainerCount: int(s.MaxPerPodContainerCount), MinimumGCAge: s.MinimumGCAge.Duration, ... }
最開始的參數(shù)都來(lái)源于KubeletServer中的KubeletConfiguration結(jié)構(gòu),相關(guān)的參數(shù)如下:
type KubeletConfiguration struct { ... // containerGC會(huì)回收已經(jīng)結(jié)束的container,但是該container結(jié)束后必須要停留 // 大于MinimumGCAge時(shí)間才能被回收。 default: 1min MinimumGCAge unversioned.Duration `json:"minimumGCAge"` // 用于指定每個(gè)已經(jīng)結(jié)束的Pod最多可以存在containers的數(shù)量,default: 2 MaxPerPodContainerCount int32 `json:"maxPerPodContainerCount"` // 集群最大支持的container數(shù)量 MaxContainerCount int32 `json:"maxContainerCount"` }
而該入?yún)⒌某跏蓟€是需要回到cmd/kubelet/app/options/options.go中的NewKubeletServer()接口,實(shí)際初始化如下:
func NewKubeletServer() *KubeletServer { ... MaxContainerCount: 240, MaxPerPodContainerCount: 2, MinimumGCAge: unversioned.Duration{Duration: 1 * time.Minute},
從上面的初始化可以看出:
該節(jié)點(diǎn)可以創(chuàng)建的最大container數(shù)量是240
每個(gè)Pod最大可以容納2個(gè)containers
container結(jié)束之后,至少需要在1分鐘之后才能被containerGC回收
所以基本的containerGC策略就明白了。
containerGC初始化策略結(jié)構(gòu)初始化完之后,還要進(jìn)行最后一步containerGC結(jié)構(gòu)初始化,需要進(jìn)入pkg/kubelet/kubelet.go的NewMainKubelet()接口查看:
func NewMainKubelet(...) { ... // setup containerGC containerGC, err := kubecontainer.NewContainerGC(klet.containerRuntime, containerGCPolicy) if err != nil { return nil, err } klet.containerGC = containerGC ... }
繼續(xù)查看NewContainerGC(),該接口在pkg/kubelet/container/container_gc.go中,看下干了啥:
func NewContainerGC(runtime Runtime, policy ContainerGCPolicy) (ContainerGC, error) { if policy.MinAge < 0 { return nil, fmt.Errorf("invalid minimum garbage collection age: %v", policy.MinAge) } return &realContainerGC{ runtime: runtime, policy: policy, }, nil }
接口很簡(jiǎn)單,根據(jù)之前的策略結(jié)構(gòu)體又初始化了一個(gè)realContainerGC結(jié)構(gòu),可以看出該接口就比較完整了,可以想象一下需要進(jìn)行container的回收的話,必須要用到runtime的接口(比如查看當(dāng)前容器狀態(tài),刪除容器等操作),所以結(jié)構(gòu)中帶入實(shí)際使用的runtime是必然的。
可以關(guān)注下該對(duì)象支持的方法,后面會(huì)用到。
所有的參數(shù)初始化結(jié)束后,需要開始進(jìn)入真正的GC啟動(dòng)流程,該步驟上面講imageManager時(shí)已經(jīng)提及,這里直接進(jìn)入正題。
啟動(dòng)containerGC的接口是StartGarbageCollection(),具體實(shí)現(xiàn)如下:
func (kl *Kubelet) StartGarbageCollection() { go wait.Until(func() { if err := kl.containerGC.GarbageCollect(kl.sourcesReady.AllReady()); err != nil { glog.Errorf("Container garbage collection failed: %v", err) } }, ContainerGCPeriod, wait.NeverStop) go wait.Until(func() { if err := kl.imageManager.GarbageCollect(); err != nil { glog.Errorf("Image garbage collection failed: %v", err) } }, ImageGCPeriod, wait.NeverStop) }
接下來(lái)我們一起看下containerGC的GarbageCollect()接口,但要找到這個(gè)接口的話,我們得回到之前初始化containerGC的步驟。
實(shí)際初始化containerGC時(shí)真正返回的是realContainerGC結(jié)構(gòu),所以GarbageCollect()是該結(jié)構(gòu)的方法:
func (cgc *realContainerGC) GarbageCollect(allSourcesReady bool) error { return cgc.runtime.GarbageCollect(cgc.policy, allSourcesReady) }
看到這里,發(fā)現(xiàn)containerGC的套路跟imageManager一樣,所以一招鮮吃遍天。
我們使用的runtime就是docker,所以需要去找docker的GarbageCollect()接口實(shí)現(xiàn),具體runtime的初始化可以查看之前一篇文章
Docker的GarbageCollect()接口在pkg/kubelet/dockertools/container_gc.go中:
func (cgc *containerGC) GarbageCollect(gcPolicy kubecontainer.ContainerGCPolicy, allSourcesReady bool) error { // 從所有的容器中分離出那些可以被回收的contianers // evictUnits: 可以識(shí)別的但已經(jīng)dead,并且創(chuàng)建時(shí)間大于回收策略中的minAge的containers // unidentifiedContainers: 無(wú)法識(shí)別的containers evictUnits, unidentifiedContainers, err := cgc.evictableContainers(gcPolicy.MinAge) if err != nil { return err } // 先刪除無(wú)法識(shí)別的containers for _, container := range unidentifiedContainers { glog.Infof("Removing unidentified dead container %q with ID %q", container.name, container.id) err = cgc.client.RemoveContainer(container.id, dockertypes.ContainerRemoveOptions{RemoveVolumes: true}) if err != nil { glog.Warningf("Failed to remove unidentified dead container %q: %v", container.name, err) } } // 所有資源都已經(jīng)準(zhǔn)備好之后,可以刪除那些已經(jīng)dead的containers if allSourcesReady { for key, unit := range evictUnits { if cgc.isPodDeleted(key.uid) { cgc.removeOldestN(unit, len(unit)) // Remove all. delete(evictUnits, key) } } } // 檢查所有的evictUnits, 刪除每個(gè)Pod中超出的containers if gcPolicy.MaxPerPodContainer >= 0 { cgc.enforceMaxContainersPerEvictUnit(evictUnits, gcPolicy.MaxPerPodContainer) } // 確保節(jié)點(diǎn)的最大containers數(shù)量 // 檢查節(jié)點(diǎn)containers數(shù)量是否超出了最大限制,是的話就刪除多出來(lái)的containers // 優(yōu)先刪除最先創(chuàng)建的containers if gcPolicy.MaxContainers >= 0 && evictUnits.NumContainers() > gcPolicy.MaxContainers { // 計(jì)算每個(gè)單元最多可以有幾個(gè)containers numContainersPerEvictUnit := gcPolicy.MaxContainers / evictUnits.NumEvictUnits() if numContainersPerEvictUnit < 1 { numContainersPerEvictUnit = 1 } // cgc.enforceMaxContainersPerEvictUnit(evictUnits, numContainersPerEvictUnit) // 需要?jiǎng)h除containers的話,優(yōu)先刪除最老的containers numContainers := evictUnits.NumContainers() if numContainers > gcPolicy.MaxContainers { flattened := make([]containerGCInfo, 0, numContainers) for uid := range evictUnits { // 先整合所有的containers flattened = append(flattened, evictUnits[uid]...) } sort.Sort(byCreated(flattened)) // 刪除numContainers-gcPolicy.MaxContainers個(gè)最先創(chuàng)建的contianers cgc.removeOldestN(flattened, numContainers-gcPolicy.MaxContainers) } } // 刪除containers之后,需要清除對(duì)應(yīng)的軟連接 logSymlinks, _ := filepath.Glob(path.Join(cgc.containerLogsDir, fmt.Sprintf("*.%s", LogSuffix))) for _, logSymlink := range logSymlinks { if _, err = os.Stat(logSymlink); os.IsNotExist(err) { err = os.Remove(logSymlink) if err != nil { glog.Warningf("Failed to remove container log dead symlink %q: %v", logSymlink, err) } } } return nil }User Configuration
上面通過(guò)源碼介紹了imageManager和containerGC的實(shí)現(xiàn),里面也涉及到了GC Policy的配置,我們也可以通過(guò)手動(dòng)修改kubelet的flags來(lái)改變參數(shù)默認(rèn)值。
imageManager相關(guān)配置image-gc-high-threshold: 該值表示磁盤占用率達(dá)到該值后會(huì)觸發(fā)image garbage collection。默認(rèn)值是90%
image-gc-low-threshold: 該值表示image GC嘗試以回收的方式來(lái)達(dá)到的磁盤占用率,若磁盤占用率原本就小于該值,不會(huì)觸發(fā)GC。默認(rèn)值是80%
containerGC相關(guān)配置minimum-container-ttl-duration: 表示container結(jié)束后多長(zhǎng)時(shí)間可以被GC回收,默認(rèn)是1min
maximum-dead-containers-per-container: 表示每個(gè)已經(jīng)結(jié)束的Pod中最多可以存在多少個(gè)containers,默認(rèn)值是2個(gè)
maximum-dead-containers: 表示kubelet所在節(jié)點(diǎn)最多可以保留已經(jīng)結(jié)束的containers的數(shù)量,默認(rèn)值是240
容器在停止工作后是可以被garbage collection進(jìn)行回收,但是我們也需要對(duì)containers進(jìn)行保留,因?yàn)橛行ヽontainers可能是異常停止的,而container可以保留有l(wèi)ogs或者別的游泳的數(shù)據(jù)用于開發(fā)進(jìn)行問(wèn)題定位。
根據(jù)上面的需求,我們就可以通過(guò)maximum-dead-containers-per-container和maximum-dead-containers很好的來(lái)實(shí)現(xiàn)這個(gè)目標(biāo)。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/32536.html
摘要:顧名思義就是管理磁盤空間的,實(shí)際它的實(shí)現(xiàn)較為簡(jiǎn)單,就是給所在的節(jié)點(diǎn)預(yù)留磁盤空間的,當(dāng)該節(jié)點(diǎn)磁盤空間低于該值時(shí),將拒絕的創(chuàng)建。其實(shí)就是中的接口該接口很簡(jiǎn)單,就是分別調(diào)用實(shí)現(xiàn)的兩個(gè)接口,然后判斷磁盤空間是否夠用。 源碼版本 kubernetes version: v1.3.0 簡(jiǎn)介 前一節(jié)介紹了Garbage Collection,涉及到的策略基本與磁盤資源有關(guān)。對(duì)于k8s集群如何高效的利...
摘要:在架構(gòu)中,堆內(nèi)存和垃圾回收器這兩個(gè)部分和垃圾回收相關(guān)。堆內(nèi)存在的內(nèi)存模型中,最重要的是要了解堆內(nèi)存的概念。在垃圾回收的過(guò)程中,這些對(duì)象將被從堆內(nèi)存中清除,同時(shí)它們的空間也就被回收了。 本文非原創(chuàng),翻譯自Java Garbage Collection introduction在Java中為對(duì)象分配和釋放內(nèi)存空間都是由垃圾回收線程自動(dòng)執(zhí)行完成的。和C語(yǔ)言不一樣的是Java程序員不需要手動(dòng)寫...
摘要:垃圾回收監(jiān)控和分析工具是在安裝時(shí)免費(fèi)提供的。監(jiān)控現(xiàn)在可以監(jiān)控垃圾回收過(guò)程了。至少我們可以知道程序中存在和對(duì)象內(nèi)存分配和垃圾回收相關(guān)的問(wèn)題。到此為止,關(guān)于垃圾回收的系列文章已經(jīng)完結(jié)了。 本文非原創(chuàng),翻譯自Java Garbage Collection Monitoring and Analysis在Java中為對(duì)象分配和釋放內(nèi)存空間都是由垃圾回收線程自動(dòng)執(zhí)行完成的。和C語(yǔ)言不一樣的是Ja...
摘要:執(zhí)行引擎作用執(zhí)行字節(jié)碼,或者執(zhí)行本地方法運(yùn)行時(shí)數(shù)據(jù)區(qū)其實(shí)就是指在運(yùn)行期間,其對(duì)內(nèi)存空間的劃分和分配。 雖是讀書筆記,但是如轉(zhuǎn)載請(qǐng)注明出處https://uestc-dpz.github.io..拒絕伸手復(fù)制黨 JVM Java 虛擬機(jī) Java 虛擬機(jī)(Java virtual machine,JVM)是運(yùn)行 Java 程序必不可少的機(jī)制。JVM實(shí)現(xiàn)了Java語(yǔ)言最重要的特征:即平臺(tái)...
閱讀 2771·2021-09-24 10:34
閱讀 1875·2021-09-22 10:02
閱讀 2262·2021-09-09 09:33
閱讀 1466·2021-08-13 15:02
閱讀 3277·2020-12-03 17:10
閱讀 1191·2019-08-30 15:44
閱讀 2152·2019-08-30 12:58
閱讀 3236·2019-08-26 13:40