kubernetes垃圾回收器GarbageCollector原始碼分析(一)
kubernetes版本:1.13.2
背景
由於operator建立的redis叢集,在kubernetes apiserver重啟後,redis叢集被異常刪除(包括redis exporter statefulset、redis statefulset)。刪除後operator將其重建,重新組建叢集,例項IP發生變更(中介軟體容器化,我們開發了固定IP,當statefulset刪除後,IP會被回收),導致建立叢集失敗,最終叢集不可用。
經多次復現,apiserver重啟後,通過查詢redis operator日誌,並沒有發現主動去刪除redis叢集(redis statefulset)、監控例項(redis exporter)。進一步去檢視kube-controller-manager的日誌,將其日誌級別設定--v=5,繼續復現,最終在kube-controller-manager日誌中發現如下日誌:
可以看到是garbage collector觸發刪除操作的。這個問題在apiserver正常的時候是不存在,要想弄其究竟,就得看看kube-controller-manager內建元件garbage collector這個控制器的邏輯。
由於內容偏長,分為多節來講:
①、monitors
作為生產者將變化的資源放入graphChanges
佇列;同時restMapper
定期檢測叢集內資源型別,重新整理monitors
②、runProcessGraphChanges
從graphChanges
佇列中取出變化的item
,根據情況放入attemptToDelete
佇列;runAttemptToDeleteWorker
③、
runProcessGraphChanges
從graphChanges
佇列中取出變化的item
,根據情況放入attemptToOrphan
佇列;runAttemptToOrphanWorker
取出處理該該孤立的資源;正文
想要啟用GC
,需要在kube-apiserver
和kube-controller-manager
的啟動引數中都設定--enable-garbage-collector
為true
,1.13.2
版本中預設開啟GC
。
需要注意:兩元件該引數必須保持同步。
kube-controller-manager
啟動入口,app.NewControllerManagerCommand()
controller manage
r預設啟動引數,建立* cobra.Command
物件:
func main() {
rand.Seed(time.Now().UnixNano())
//載入controller manager預設啟動引數,建立* cobra.Command物件
command := app.NewControllerManagerCommand()
//......省略.......
//執行cobra.command,並啟動controller-manager
if err := command.Execute(); err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
os.Exit(1)
}
}
以下程式碼處去啟動kube-controller-manager
:
NewDefaultComponentConfig(ports.InsecureKubeControllerManagerPort)
載入各個控制器的配置:
//NewKubeControllerManagerOptions使用預設配置建立一個新的KubeControllerManagerOptions
func NewKubeControllerManagerOptions() (*KubeControllerManagerOptions, error) {
//載入各個控制器的預設配置
componentConfig, err := NewDefaultComponentConfig(ports.InsecureKubeControllerManagerPort)
if err != nil {
return nil, err
}
s := KubeControllerManagerOptions{
Generic: cmoptions.NewGenericControllerManagerConfigurationOptions(componentConfig.Generic),
//.....省略
GarbageCollectorController: &GarbageCollectorControllerOptions{
ConcurrentGCSyncs: componentConfig.GarbageCollectorController.ConcurrentGCSyncs,
EnableGarbageCollector: componentConfig.GarbageCollectorController.EnableGarbageCollector,
},
//.....省略
}
//gc忽略的資源物件列表
gcIgnoredResources := make([]kubectrlmgrconfig.GroupResource, 0, len(garbagecollector.DefaultIgnoredResources()))
for r := range garbagecollector.DefaultIgnoredResources() {
gcIgnoredResources = append(gcIgnoredResources, kubectrlmgrconfig.GroupResource{Group: r.Group, Resource: r.Resource})
}
s.GarbageCollectorController.GCIgnoredResources = gcIgnoredResources
return &s, nil
}
// NewDefaultComponentConfig返回kube-controller管理器配置物件
func NewDefaultComponentConfig(insecurePort int32) (kubectrlmgrconfig.KubeControllerManagerConfiguration, error) {
scheme := runtime.NewScheme()
if err := kubectrlmgrschemev1alpha1.AddToScheme(scheme); err != nil {
return kubectrlmgrconfig.KubeControllerManagerConfiguration{}, err
}
if err := kubectrlmgrconfig.AddToScheme(scheme); err != nil {
return kubectrlmgrconfig.KubeControllerManagerConfiguration{}, err
}
versioned := kubectrlmgrconfigv1alpha1.KubeControllerManagerConfiguration{}
//載入預設引數
scheme.Default(&versioned)
internal := kubectrlmgrconfig.KubeControllerManagerConfiguration{}
if err := scheme.Convert(&versioned, &internal, nil); err != nil {
return internal, err
}
internal.Generic.Port = insecurePort
return internal, nil
}
// 根據Object,獲取提供的預設引數
func (s *Scheme) Default(src Object) {
if fn, ok := s.defaulterFuncs[reflect.TypeOf(src)]; ok {
fn(src)
}
}
s.defaulterFuncs型別為map[reflect.Type]func(interface{}),用於根據指標型別獲取預設值函式。該map中的資料從哪裡來的呢?
程式碼位於src\k8s.io\kubernetes\pkg\controller\apis\config\v1alpha1\zz_generated.defaults.go
可以看到預設引數中garbage collector中預設開啟gc(EnableGarbageCollector),併發數為20(ConcurrentGCSyncs)
func SetDefaults_GarbageCollectorControllerConfiguration(obj *kubectrlmgrconfigv1alpha1.GarbageCollectorControllerConfiguration) {
if obj.EnableGarbageCollector == nil {
obj.EnableGarbageCollector = utilpointer.BoolPtr(true)
}
if obj.ConcurrentGCSyncs == 0 {
obj.ConcurrentGCSyncs = 20
}
}
回到Run函式,裡面呼叫了NewControllerInitializers啟動所有控制器:
重點來到啟動garbage collector的startGarbageCollectorController函式:
func startGarbageCollectorController(ctx ControllerContext) (http.Handler, bool, error) {
//k8s 1.13.2中預設為true,可在kube-apiserver和kube-controller-manager的啟動引數中加--enable-garbage-conllector=false設定
//需保證這兩個元件中引數值一致
if !ctx.ComponentConfig.GarbageCollectorController.EnableGarbageCollector {
return nil, false, nil
}
//k8s各種原生資源物件客戶端集合(預設啟動引數中用SimpleControllerClientBuilder構建)
gcClientset := ctx.ClientBuilder.ClientOrDie("generic-garbage-collector")
discoveryClient := cacheddiscovery.NewMemCacheClient(gcClientset.Discovery())
//生成rest config
config := ctx.ClientBuilder.ConfigOrDie("generic-garbage-collector")
dynamicClient, err := dynamic.NewForConfig(config)
if err != nil {
return nil, true, err
}
// Get an initial set of deletable resources to prime the garbage collector.
//獲取一組初始可刪除資源以填充垃圾收集器。
deletableResources := garbagecollector.GetDeletableResources(discoveryClient)
ignoredResources := make(map[schema.GroupResource]struct{})
//忽略gc的資源型別
for _, r := range ctx.ComponentConfig.GarbageCollectorController.GCIgnoredResources {
ignoredResources[schema.GroupResource{Group: r.Group, Resource: r.Resource}] = struct{}{}
}
garbageCollector, err := garbagecollector.NewGarbageCollector(
dynamicClient,
ctx.RESTMapper,
deletableResources,
ignoredResources,
ctx.InformerFactory,
ctx.InformersStarted,
)
if err != nil {
return nil, true, fmt.Errorf("Failed to start the generic garbage collector: %v", err)
}
// Start the garbage collector.
//啟動引數中預設是20個協程
workers := int(ctx.ComponentConfig.GarbageCollectorController.ConcurrentGCSyncs)
//啟動monitors和deleteWorkers、orphanWorkers
go garbageCollector.Run(workers, ctx.Stop)
// Periodically refresh the RESTMapper with new discovery information and sync
// the garbage collector.
//使用新的發現資訊定期重新整理RESTMapper並同步垃圾收集器。
go garbageCollector.Sync(gcClientset.Discovery(), 30*time.Second, ctx.Stop)
//gc提供debug dot grap依賴關係圖介面
return garbagecollector.NewDebugHandler(garbageCollector), true, nil
}
該函式主要作用有:
1、deletableResources := garbagecollector.GetDeletableResources(discoveryClient)獲取叢集內所有可刪除的資源物件;排除掉忽略的資源物件。
2、構建garbageCollector結構體物件;
3、garbageCollector.Run(workers, ctx.Stop)啟動一個monitors用來監聽資源物件的變化(對應的由runProcessGraphChanges死迴圈處理),和預設20個deleteWorkers協程處理可刪除的資源物件、20個orphanWorkers協程處理孤兒物件。
4、garbageCollector.Sync(gcClientset.Discovery(), 30*time.Second, ctx.Stop) 定時去獲取一個叢集內是否有新型別的資源物件的加入,並重新重新整理monitors,以監聽新型別的資源物件。
5、garbagecollector.NewDebugHandler(garbageCollector)註冊debug介面,用來提供獲取dot流程圖介面:
curl http://127.0.0.1:10252/debug/controllers/garbagecollector/graph?uid=11211212edsaddkqedmk12
使用graphviz提供的dot.exe可以生成svg格式的圖,可用google瀏覽器檢視如下:
// curl http://127.0.0.1:10252/debug/controllers/garbagecollector/graph?uid=11211212edsaddkqedmk12
func (h *debugHTTPHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
if req.URL.Path != "/graph" {
http.Error(w, "", http.StatusNotFound)
return
}
var graph graph.Directed
if uidStrings := req.URL.Query()["uid"]; len(uidStrings) > 0 {
uids := []types.UID{}
for _, uidString := range uidStrings {
uids = append(uids, types.UID(uidString))
}
graph = h.controller.dependencyGraphBuilder.uidToNode.ToGonumGraphForObj(uids...)
} else {
graph = h.controller.dependencyGraphBuilder.uidToNode.ToGonumGraph()
}
//生成dot流程圖資料,用graphviz工具中的dot.exe工具轉換為svg圖(用google瀏覽器開啟)或者png圖
//API參考:https://godoc.org/gonum.org/v1/gonum/graph
//graphviz下載地址:https://graphviz.gitlab.io/_pages/Download/Download_windows.html
//dot.exe test.dot -T svg -o test.svg
data, err := dot.Marshal(graph, "full", "", " ", false)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Write(data)
w.WriteHeader(http.StatusOK)
}
GarbageCollector通過restMapper定期重置可刪除的資源型別,更新GraphBuilder中的monitors,monitors將建立所有資源型別的變更通知回撥函式,將變化的資源物件加入到GraphBuilder的graphChanges佇列,GraphBuilder的runProcessGraphChanges()會一直從佇列中獲取變化,構建一個快取物件之間依賴關係的圖形,以及觸發dependencyGraphBuilder將可能被垃圾收集的物件排隊到attemptToDelete
佇列,並將其依賴項需要孤立的物件排隊到attemptToOrphan
佇列。GarbageCollector具有使用這兩個佇列的工作人員runAttemptToDeleteWorker和runAttemptToOrphanWorker死迴圈,分別從attemptToDelete
佇列和attemptToOrphan
佇列取出,向API伺服器傳送請求以相應地刪除更新物件。
// GarbageCollector執行反射器來監視託管API物件的更改,將結果彙總到單執行緒dependencyGraphBuilder,
// 構建一個快取物件之間依賴關係的圖形。由圖變化觸發,dependencyGraphBuilder將可能被垃圾收集的物件
// 排隊到`attemptToDelete`佇列,並將其依賴項需要孤立的物件排隊到`attemptToOrphan`佇列。
// GarbageCollector具有使用這兩個佇列的工作人員,向API伺服器傳送請求以相應地刪除更新物件。
// 請注意,讓dependencyGraphBuilder通知垃圾收集器確保垃圾收集器使用至少與傳送通知一樣最新的圖形進行操作。
type GarbageCollector struct {
// resettableRESTMapper是一個RESTMapper,它能夠在discovery資源型別時重置自己
restMapper resettableRESTMapper
// dynamicClient提供操作叢集內所有資源物件的介面方法,包括k8s內建、CRD生成的自定義資源
dynamicClient dynamic.Interface
//垃圾收集器嘗試在時間成熟時刪除attemptToDelete佇列中的item
attemptToDelete workqueue.RateLimitingInterface
//垃圾收集器嘗試孤立attemptToOrphan佇列中item的依賴項,然後刪除item
attemptToOrphan workqueue.RateLimitingInterface
dependencyGraphBuilder *GraphBuilder
// 有owner的資源物件,才會給absentOwnerCache填充不存在的Owner資訊
absentOwnerCache *UIDCache
sharedInformers informers.SharedInformerFactory
workerLock sync.RWMutex
}
// GraphBuilder:基於informers提供的事件,GraphBuilder更新
// uidToNode,一個快取我們所知的依賴關係的圖,並將
// 項放入attemptToDelete和attemptToOrphan佇列
type GraphBuilder struct {
restMapper meta.RESTMapper
//每個監視器列表/監視資源,結果彙集到dependencyGraphBuilder
monitors monitors
monitorLock sync.RWMutex
// informersStarted is closed after after all of the controllers have been initialized and are running.
// After that it is safe to start them here, before that it is not.
// informersStarted在所有控制器初始化並執行後關閉。之後在這裡啟動它們是安全的,在此之前它不是。
informersStarted <-chan struct{}
// stopCh drives shutdown. When a receive from it unblocks, monitors will shut down.
// This channel is also protected by monitorLock.
// stopCh驅動器關閉當來自它的接收解除阻塞時,監視器將關閉。 此channel也受monitorLock保護。
stopCh <-chan struct{}
// running tracks whether Run() has been called.
// it is protected by monitorLock.
//執行軌道是否已呼叫Run()它受monitorLock保護。
running bool
dynamicClient dynamic.Interface
// monitors are the producer of the graphChanges queue, graphBuilder alters
// the in-memory graph according to the changes.
// monitor是graphChanges佇列的生成者,graphBuilder根據更改改變了記憶體中的圖形。
graphChanges workqueue.RateLimitingInterface
// uidToNode doesn't require a lock to protect, because only the
// single-threaded GraphBuilder.processGraphChanges() reads/writes it.
//uidToNode不需要鎖保護,因為只有單執行緒GraphBuilder.processGraphChanges()讀寫它。
uidToNode *concurrentUIDToNode
// GraphBuilder is the producer of attemptToDelete and attemptToOrphan, GC is the consumer.
// GraphBuilder是attemptToDelete和attemptToOrphan的生產者,GC是消費者。
attemptToDelete workqueue.RateLimitingInterface
attemptToOrphan workqueue.RateLimitingInterface
// GraphBuilder and GC share the absentOwnerCache. Objects that are known to
// be non-existent are added to the cached.
// GraphBuilder和GC共享absentOwnerCache。已知不存在的物件將新增到快取中。
absentOwnerCache *UIDCache
//所有k8s資源物件集的informer
sharedInformers informers.SharedInformerFactory
//監視器忽略的資源物件集
ignoredResources map[schema.GroupResource]struct{}
}
建立NewGarbageCollector結構體:
func NewGarbageCollector(
dynamicClient dynamic.Interface,
mapper resettableRESTMapper,
deletableResources map[schema.GroupVersionResource]struct{},
ignoredResources map[schema.GroupResource]struct{},
sharedInformers informers.SharedInformerFactory,
informersStarted <-chan struct{},
) (*GarbageCollector, error) {
attemptToDelete := workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "garbage_collector_attempt_to_delete")
attemptToOrphan := workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "garbage_collector_attempt_to_orphan")
absentOwnerCache := NewUIDCache(500)
gc := &GarbageCollector{
dynamicClient: dynamicClient,
restMapper: mapper,
attemptToDelete: attemptToDelete,
attemptToOrphan: attemptToOrphan,
absentOwnerCache: absentOwnerCache,
}
gb := &GraphBuilder{
dynamicClient: dynamicClient,
informersStarted: informersStarted,
restMapper: mapper,
graphChanges: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "garbage_collector_graph_changes"),
uidToNode: &concurrentUIDToNode{
uidToNode: make(map[types.UID]*node),
},
attemptToDelete: attemptToDelete,
attemptToOrphan: attemptToOrphan,
absentOwnerCache: absentOwnerCache,
sharedInformers: sharedInformers,
ignoredResources: ignoredResources,
}
//初始化各個資源物件的monitors,啟動各資源物件的監聽器,變化時觸發回撥,將其加入graphChanges 佇列
if err := gb.syncMonitors(deletableResources); err != nil {
utilruntime.HandleError(fmt.Errorf("failed to sync all monitors: %v", err))
}
gc.dependencyGraphBuilder = gb
return gc, nil
}
主要功能:
1、構建GarbageCollector結構體;
2、構建依賴結構圖維護結構體GraphBuilder,和GarbageCollector共用attemptToDelete和attemptToOrphan佇列,GraphBuilder作為生產著將適當資源放到attemptToDelete或者attemptToOrphan佇列,供GarbageCollector中的worker進行消費;
3、初始化各個資源物件的monitors,啟動各資源物件的監聽器,變化時觸發回撥,將其加入graphChanges 佇列。
gb.syncMonitors(deletableResources)
方法中最主要的是c, s, err := gb.controllerFor(resource, kind)
func (gb *GraphBuilder) controllerFor(resource schema.GroupVersionResource, kind schema.GroupVersionKind) (cache.Controller, cache.Store, error) {
handlers := cache.ResourceEventHandlerFuncs{
// add the event to the dependencyGraphBuilder's graphChanges.
// 將事件新增到dependencyGraphBuilder的graphChanges中。
AddFunc: func(obj interface{}) {
event := &event{
eventType: addEvent,
obj: obj,
gvk: kind,
}
gb.graphChanges.Add(event)
},
UpdateFunc: func(oldObj, newObj interface{}) {
// TODO: check if there are differences in the ownerRefs,
// finalizers, and DeletionTimestamp; if not, ignore the update.
//TODO:檢查ownerRefs, finalizers和DeletionTimestamp是否存在差異;如果沒有,請忽略更新。
event := &event{
eventType: updateEvent,
obj: newObj,
oldObj: oldObj,
gvk: kind,
}
gb.graphChanges.Add(event)
},
DeleteFunc: func(obj interface{}) {
// delta fifo may wrap the object in a cache.DeletedFinalStateUnknown, unwrap it
// delta fifo可以將物件包裝在cache.DeletedFinalStateUnknown中,解包它
if deletedFinalStateUnknown, ok := obj.(cache.DeletedFinalStateUnknown); ok {
obj = deletedFinalStateUnknown.Obj
}
event := &event{
eventType: deleteEvent,
obj: obj,
gvk: kind,
}
gb.graphChanges.Add(event)
},
}
shared, err := gb.sharedInformers.ForResource(resource)
if err == nil {
klog.V(4).Infof("using a shared informer for resource %q, kind %q", resource.String(), kind.String())
// need to clone because it's from a shared cache
shared.Informer().AddEventHandlerWithResyncPeriod(handlers, ResourceResyncTime)
return shared.Informer().GetController(), shared.Informer().GetStore(), nil
} else {
//獲取資源物件時出錯會到這裡,比如非k8s內建RedisCluster、clusterbases、clusters、esclusters、volumeproviders、stsmasters、appapps、mysqlclusters、brokerclusters、clustertemplates;
//內建的networkPolicies、apiservices、customresourcedefinitions
klog.V(4).Infof("unable to use a shared informer for resource %q, kind %q: %v", resource.String(), kind.String(), err)
}
// TODO: consider store in one storage.
// TODO: 考慮儲存在一個儲存中。
klog.V(5).Infof("create storage for resource %s", resource)
//上面失敗的資源物件的store和controller
store, monitor := cache.NewInformer(
listWatcher(gb.dynamicClient, resource),
nil,
ResourceResyncTime,
// don't need to clone because it's not from shared cache
//不需要克隆,因為它不是來自共享快取
handlers,
)
return monitor, store, nil
}
該方法主要功能是:
1、將新增、更改、刪除的資源物件構建為event結構體,放入GraphBuilder的graphChanges佇列裡,最終被runProcessGraphChanges這個worker消費;
2、構建大多數內建資源的SharedInformerFactory,構建失敗的用cache.NewInformer構建(通過CRD定義的物件以及部分k8s內建物件)
程式碼繼續回到k8s.io\kubernetes\cmd\kube-controller-manager\app\core.go中的startGarbageCollectorController
中,看garbageCollector.Run(workers, ctx.Stop)
方法:
func (gc *GarbageCollector) Run(workers int, stopCh <-chan struct{}) {
defer utilruntime.HandleCrash()
defer gc.attemptToDelete.ShutDown()
defer gc.attemptToOrphan.ShutDown()
defer gc.dependencyGraphBuilder.graphChanges.ShutDown()
klog.Infof("Starting garbage collector controller")
defer klog.Infof("Shutting down garbage collector controller")
//協程執行生產者monitors
go gc.dependencyGraphBuilder.Run(stopCh)
//等待dependencyGraphBuilder快取開始同步
if !controller.WaitForCacheSync("garbage collector", stopCh, gc.dependencyGraphBuilder.IsSynced) {
return
}
//垃圾收集器:所有資源監視器都已同步。繼續收集垃圾
klog.Infof("Garbage collector: all resource monitors have synced. Proceeding to collect garbage")
// gc workers
//協程執行消費者DeleteWorkers和OrphanWorkers
for i := 0; i < workers; i++ {
//預設引數為20個併發協程嘗試delete worker
go wait.Until(gc.runAttemptToDeleteWorker, 1*time.Second, stopCh)
//預設引數為20個併發協程嘗試orphan worker
go wait.Until(gc.runAttemptToOrphanWorker, 1*time.Second, stopCh)
}
<-stopCh
}
gc.dependencyGraphBuilder.Run(stopCh)
主要功能:
1、gb.startMonitors()啟動監聽資源變化的informer;
2、wait.Until(gb.runProcessGraphChanges, 1*time.Second, stopCh)開啟從佇列GraphBuilder.graphChanges中消費的worker
啟動20個runAttemptToDeleteWorker和20個runAttemptToOrphanWorker
參考:
k8s官方文件garbage-collection英文版:
https://kubernetes.io/docs/concepts/workloads/controllers/garbage-collection/
依賴圖示生成庫gonum Api文件:
https://godoc.org/gonum.org/v1/gonum/graph
graphviz下載:
https://graphviz.gitlab.io/_pages/Download/Download_windows.html
本公眾號免費提供csdn下載服務,海量IT學習資源,如果你準備入IT坑,勵志成為優秀的程式猿,那麼這些資源很適合你,包括但不限於java、go、python、springcloud、elk、嵌入式 、大資料、面試資料、前端 等資源。同時我們組建了一個技術交流群,裡面有很多大佬,會不定時分享技術文章,如果你想來一起學習提高,可以公眾號後臺回覆【2】,免費邀請加技術交流群互相學習提高,會不定期分享程式設計IT相關資源。
掃碼關注,精彩內容第一時間推給你
相關推薦
kubernetes垃圾回收器GarbageCollector原始碼分析(一)
kubernetes版本:1.13.2 背景 由於operator建立的redis叢集,在kubernetes apiserver重啟後,redis叢集被異常刪除(包括redis exporter statefulset、redis statefulset)。刪除後operator將其重建,重新組建叢集,
Android系統播放器MediaPlayer原始碼分析(一)
前言 對於MediaPlayer播放器的原始碼分析內容相對來說比較多,會從Java->JNI->C/C++慢慢分析,後面會慢慢更新。另外,部落格只作為自己學習記錄的一種方式,對於其他的不過多的評論。 MediaPlayerDemo public class MainA
kubernetes垃圾回收器GarbageCollector Controller原始碼分析(二)
kubernetes版本:1.13.2 接上一節:kubernetes垃圾回收器GarbageCollector Controller原始碼分析(一) 主要步驟 GarbageCollector Controller原始碼主要分為以下幾部分: monitors作為生產者將變化的資源放入graphChan
Flume NG原始碼分析(一)基於靜態properties檔案的配置模組
日誌收集是網際網路公司的一個重要服務,Flume NG是Apache的頂級專案,是分散式日誌收集服務的一個開源實現,具有良好的擴充套件性,與其他很多開源元件可以無縫整合。搜了一圈發現介紹Flume NG的文章有不少,但是深入分析Flume NG原始碼的卻沒有。準備寫一個系列分析一下Flume NG的
GCC原始碼分析(一)——介紹與安裝
原文連結:http://blog.csdn.net/sonicling/article/details/6702031 上半年一直在做有關GCC和LD的專案,到現在還沒做完。最近幾天程式設計的那臺電腦壞了,所以趁此間隙寫一點相關的分析和
Glide原始碼分析(一)從用法來看之with方法
繼續啃原始碼,用過Glide的人,肯定都覺得它好好用,我們一般只需要幾行程式碼,就可以達到我們想要的效果,可以在這個背後是什麼呢?就需要我們來看了。 我一般看原始碼,我喜歡先從用法來看,然後一步一步的再細扣,所以就先從用法來看Glide的整體流程。 用過Glide的人,用下面這段
zigbee 之ZStack-2.5.1a原始碼分析(一)
先看main, 在檔案Zmain.c裡面 main osal_init_system(); osalInitTasks(); ... ... SampleApp_Init( taskID ); // 使用者定義的任務
Docker Client原始碼分析(一)
主要內容: Docker Client在Docker中的定位,以及Docker Client原始碼的初步分析。 本文選取Docker拆分為DockerCE(社群版)和DockerEE(企業版)之後的Docker-CE的第一個穩定版本v17.06.0-ce。 https://github.com/docker
Hibernate使用及原始碼分析(一)
Hibernate使用及原始碼分析(一) 本篇文章主要通過hibernate初級使用分析一下原始碼,只是給初學者一點小小的建議,不喜勿噴,謝謝! hibernate環境搭建 簡單使用 原始碼走讀 一 hibernate環境搭建 這裡直接
SpringCloud原始碼分析(一)--客戶端搭建
一、前言 上一節的註冊中心搭建完成了,本節開始搭建客戶端,其實對於springcloud的Eureka註冊中心而言,他本身就是服務端也是客戶端,我們上節待見服務端註冊中心的時候,已經通過配置來設定其不向自己註冊,和不去檢索服務的功能,保持了其作為服務註冊中心的相對的功能單一性。 二、pom檔案
Vue原始碼分析(一):入口檔案
Vue原始碼分析(一):入口檔案 首先開啟命令列,從github下載原始碼,下載到自己的工作目錄。 git clone https://github.com/vuejs/vue.git 這裡我下載的是2.5.17版本的,vue 原始碼是由各種模組用 rollup 工具
okhttp原始碼分析(一)——基本流程(超詳細)
1.okhttp原始碼分析(一)——基本流程(超詳細) 2.okhttp原始碼分析(二)——RetryAndFollowUpInterceptor過濾器 3.okhttp原始碼分析(三)——CacheInterceptor過濾器 4.okhttp原始碼分析(四)——Conn
spring事務管理原始碼分析(一)配置和事務增強代理的生成流程
在本篇文章中,將會介紹如何在spring中進行事務管理,之後對其內部原理進行分析。主要涉及 @EnableTransactionManagement註解為我們做了什麼? 為什麼標註了@Transactional註解的方法就可以具有事務的特性,保持了資料的ACID特性?spring到底是如何具有這樣
Android7.1 [Camera] Camera Hal 原始碼分析(一)
原始碼平臺:rk3399 命令列ls看下原始碼的結構 hardware/rockchip/camera/CameraHal: lib目錄 原始碼的檔案看起來有點多,我們看看Android.mk檔案, 這些檔案最終編譯成camera.rk30bo
Cat原始碼分析(一):Client端
前言 cat的Client端所做的工作就是收集埋點資訊,將埋點資訊處理成messageTree,放到傳送佇列中,在啟動另一個執行緒,非同步消費佇列,進行訊息的傳送。 本文涉及到三個內容: 客戶端初始化:做了哪些準備工作 message的建立過程 客戶端的傳
laravel框架原始碼分析(一)自動載入
一、前言 使用php已有好幾年,laravel的使用也是有好長時間,但是一直對於框架原始碼的理解不深,原因很多,歸根到底還是php基礎不紮實,所以原始碼看起來也比較吃力。最近有時間,所以開啟第5、6遍的框架原始碼探索之旅,前面幾次都是看了一些就放棄,希望這次能夠看完。每一次看原始碼都會有新的收穫,因為框
github上hamsternz/FPGA_DisplayPort 的VHDL原始碼分析(一)
原始碼來源於https://github.com/hamsternz/FPGA_DisplayPort。由於我也是第一次接觸這個介面,所以文中肯定有我理解錯誤的地方,懇請指正。要看懂程式碼首先還是要對協議有一定了解。所以我做的原始碼分析中會和協議結合起來。 激勵檔案test_source_800
vue-element-admin原始碼分析(一)
這兩天看花褲衩大大的手摸手系列,使用vue+element+vuex+axios實現了一個後臺模板(專案地址),在閱讀原始碼的過程中收益匪淺,以下做一些筆記。(由於是學習大大專案的思想,所以略去了很多大大的程式碼)。 這裡只是做一個登陸頁面,然後能提交資料給後臺
lua原始碼分析(一)揭開 table 的神祕面紗
友情提醒:閱讀本文前請先確保自己對雜湊表有足夠深入的理解,雜湊表的詳解可以參見以下這篇文章:Redis底層詳解(一) 雜湊表和字典。 lua 底層 table (也叫陣列, 物件
subsampling-scale-image-view部分載入bitmap原始碼分析(一)
subsampling-scale-image-view原始碼分析背景介紹使用原始碼分析總結參考 背景 對於安卓開發人員,最頭疼的問題就是記憶體問題了,而記憶體問題又當屬bitmap最頭疼,雖然說現在市面上已經有越來越多成熟的圖片載入框架,像Fresco,Gli