1. 程式人生 > >STL學習筆記(1)空間配置器 allocator

STL學習筆記(1)空間配置器 allocator

1 簡述

    STL其他元件都是存放在空間配置器配置的空間中,此處空間可以是記憶體,也可以是磁碟或其他輔助儲存介質。
    allocator負責記憶體的分配和釋放,以及負責物件的構造和析構,兩個操作時分開的。
    每個容器都已經制定了預設的空間配置器Alloc,如下圖所示。
在這裡插入圖片描述
若要使用自己的空間配置器則必須vector<int,my_alloc> mv;

2 標準介面

// 以下幾種自定義型別是一種type_traits技巧,暫時不需要了解
allocator::value_type
allocator::pointer
allocator::const_pointer
allocator::
reference allocator::const_reference allocator::size_type allocator::difference allocator::rebind // 一個巢狀的(nested)class template,class rebind<U>擁有唯一成員other,那是一個typedef,代表allocator<U> allocator::allocator() // 預設建構函式 allocator::allocator(const allocator&) // 拷貝建構函式 template <class U>
allocator::allocator(const allocator<U>&) // 泛化的拷貝建構函式 allocator::~allocator() // 解構函式 pointer allocator::address(reference x) const // 返回某個物件的地址,a.address(x)等同於&x const_pointer allocator::address(const_reference x) const // 返回某個const物件的地址,a.address(x)等同於&x pointer allocator::allocate
(size_type n, const void* = 0) // 配置空間,足以儲存n個T物件。第二個引數是個提示。實現上可能會利用它來增進區域性(locality),或完全忽略之 void allocator::deallocate(pointer p, size_type n)// 釋放先前配置的空間 size_type allocator:maxsize() const// 返回可成功配置的最大量 void allocator::construct(pointer p, const T& x) //在p指向位置 呼叫物件的建構函式,等同於 new((void*)p) T(x) void allocator::destroy(pointer p)// 呼叫物件的解構函式,等同於 p->~T()

3 空間配置器申請的空間均僅僅是空間(如僅分配記憶體而未構造物件)

這裡說明幾種申請記憶體的區別

  • A *a = (A*)(::operator new A ((size_t) (size * sizeof(A)));
      呼叫全域性operator new(size_t size)僅僅申請記憶體,然後返回指標。allocate中使用。
  • void *mem = operator new A (sizeof(T1),p);
      借用p指向的記憶體處大小為sizeof(T1)的記憶體,返回void*指標。
  • A *a = new A (...);
      ①申請記憶體(與operator new相同)
      ②呼叫A(…)構造物件
      ③返回指標
//Complex* pc=new Complex(1,2)相當於
		try{
			void* mem = operator new(size(Complex));
			Complex* pc=static_case<Complex*>(mem);
			pc->Complex()::Complex(1,2);
		}
		catch(std::bad_alloc){ ... }
  • new(p) T1(value);
      為已申請記憶體*p構造T1。construct時使用。相當於
		try{
			void* mem = operator new(size(T1),p);
			p* pc=static_case<T1*>(mem);
			pc->T1()::T1();
		}
		catch{ ... }

4 SGI空間配置器

SGI的空間配置器名稱為alloc,而非allocator,不接受任何引數。

vector<int,allocator<int>> iv;
vector<int,alloc> iv;

我們所習慣的c++記憶體配置操作和釋放操作是使用newdelete來完成的:

class Foo { ... };
Foo* pf = new Foo; // 配置記憶體,然後構造物件
delete pf; // 將物件析構,然後釋放記憶體

如上一部分所說,其中的new 操作符(new operator)包含兩階段操作:
  (1)呼叫operator new配置記憶體
  (2)呼叫Foo::Foo( )建構函式構造物件內容。
delete操作符同樣也包含兩階段操作:
  (1)呼叫Foo::~Foo( )解構函式將物件析構。
  (2)呼叫operator delete釋放記憶體
STL allocator 將這兩階段操作區分開來。
記憶體配置操作由 alloc::allocate() 負責,記憶體釋放操作由 alloc::deallocate() 負責;
物件構造操作由 ::construct() 負責,物件析構操作由 ::destroy() 負責。

//負責記憶體空間的配置與釋放;
<stl_alloc.h>//檔案中定義了一、二兩級配置器,彼此合作,配置器名為alloc。

//負責物件內容的配置與釋放
<stl_construct.h>//全域性函式construct()和destroy(),負責物件的構造和析構。

//用來填充fill或複製copy大塊記憶體資料
<stl_uninitialized.h>//uninitialized_copy();uninitialized_fill();uninitialized_fill_n
uninitialized_copy(first, last, result) //將[first,last)範圍內的物件複製到result處;
uninitiated_fill(first, last, X) //將[first,last)範圍內的記憶體用物件X的副本填充;
uninitiated_fill_n(first, n, X) //將first開始的n個連續的記憶體空間用X的副本填充;


4.1 構造與析構工具:construct()和destroy()

  • construct()僅僅負責構造物件,需要提前用allocate()申請記憶體。兩操作合起來相當於new。
      construct()接受一個指標p和初值value,該函式將初值設定到所指空間上;
  • destroy()僅僅負責析構物件,需要之後用deallocate()釋放記憶體。兩操作合起來相當於delete。
      destroy()有兩個版本:
      
      1、接收一個指標,準備將該指標所指之物析構掉。直接呼叫該物件的解構函式;
      2、接收first和last兩個迭代器,準備將[first,last)範圍內的所有物件析構掉。
    利用value_type()獲取迭代器所指物件的型別,利用__type_traits判斷該型別的解構函式是否無關痛癢。若是__true_type,則什麼也不做,反之若是__false_type則迴圈訪問,對每個物件呼叫解構函式。
#ifndef __SGI_STL_INTERNAL_CONSTRUCT_H
#define __SGI_STL_INTERNAL_CONSTRUCT_H
#include <new.h>		// 欲使用 placement new,需先含入此檔

template <class T1, class T2>
inline void construct(T1* p, const T2& value) {
  new (p) T1(value); 	// placement new; 呼叫 T1::T1(value);
}

// 以下是 destroy() 第一版本,接受一個指標。
template <class T>
inline void destroy(T* pointer) {
    pointer->~T();	// 喚起 dtor ~T()
}

// 如果元素的數值型別(value type)有 non-trivial destructor…
template <class ForwardIterator>
inline void
__destroy_aux(ForwardIterator first, ForwardIterator last, __false_type) {
  for ( ; first < last; ++first)
    destroy(&*first);
}

// 如果元素的數值型別(value type)有 trivial destructor…
template <class ForwardIterator> 
inline void __destroy_aux(ForwardIterator, ForwardIterator, __true_type) {}

// 判斷元素的數值型別(value type)是否有 trivial destructor
template <class ForwardIterator, class T>
inline void __destroy(ForwardIterator first, ForwardIterator last, T*) {
  typedef typename __type_traits<T>::has_trivial_destructor trivial_destructor;
  __destroy_aux(first, last, trivial_destructor());//根據trivial_destructor()不同返回值,呼叫上面兩個函式之一。
}

// 以下是 destroy() 第二版本,接受兩個迭代器。此函式是設法找出元素的數值型別,
// 進而利用 __type_traits<> 求取最適當措施。
template <class ForwardIterator>
inline void destroy(ForwardIterator first, ForwardIterator last) {
  __destroy(first, last, value_type(first));
}

// 以下是destroy() 第二版本針對迭代器為 char* 和 wchar_t* 的特化版
inline void destroy(char*, char*) {}
inline void destroy(wchar_t*, wchar_t*) {}

__STL_END_NAMESPACE

#endif /* __SGI_STL_INTERNAL_CONSTRUCT_H */

值得注意的是,關於trivial_destructor(),該函式相當於__type_traits::has_trivial_destructor。
如果使用者不定義解構函式,而是用系統自帶的,則說明,解構函式基本沒有什麼用(但預設會被呼叫)我們稱之為trivial
destructor
。反之,如果特定定義了解構函式,則說明需要在釋放空間之前做一些事情,則這個解構函式稱為non-trivial
destructor。 通過has_trivial_destructor()返回值的不同,呼叫不同的函式。

使用上述trait變成技法的原因是我們不知道first到last的範圍有多大,若很大,而每個物件的解構函式是無關痛癢的(即trivial destructor),那麼會極大的降低效率。

4.2 空間的配置和釋放:std::alloc

在這裡插入圖片描述

SGI STL在<stl_alloc.h>中定義了兩級配置器。預設使用的是一級空間配置器。
第一級空間配置器__malloc_alloc_template使用malloc/free函式,當分配的空間大小超過128 bytes的時候使用第一級空間配置器;
第二級空間配置器__default_alloc_template使用了記憶體池技術,當分配的空間大小小於128 bytes的時候,將使用第二級空間配置器。
關於一級空間配置器宇二級空間配置器的封裝方式與使用方式如下圖:
在這裡插入圖片描述

4.3 第一級配置器 __malloc_alloc_template

第一級其實沒什麼好說的,都是直接使用malloc(), free(), realloc()等C函式執行實際的記憶體配置、釋放、重配置.
比較值得講一下的是對C++的new-handler機制進行模擬的部分,即在記憶體分配失敗時呼叫指定函式。
失敗時呼叫的函式是static void (* __malloc_alloc_oom_handler)() 所指向的指標,當然再失敗時先呼叫static void *oom_malloc(size_t);static void *oom_realloc(void *, size_t);,然後再此函式中再進一步呼叫static void (* __malloc_alloc_oom_handler)()
對該函式指標進行設定要使用static void (* set_malloc_handler(void (*f)()))() {/*...*/ },這也是個函式指標,同時它的引數也是函式指標,傳入新的函式指標。

// 以下是第一級配置器。
// 注意,無「template型別引數」。「非型別引數」inst完全沒派上用場。
template <int inst>
class __malloc_alloc_template {

private:

static void *oom_malloc(size_t);

static void *oom_realloc(void *, size_t);

#ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG
    static void (* __malloc_alloc_oom_handler)();//分配失敗後呼叫函式指標指向的函式
#endif

public:

static void * allocate(size_t n)
{
    void *result = malloc(n);	// 第一級配置器直接使用 malloc()
    if (0 == result) result = oom_malloc(n);
    return result;
}

static void deallocate(void *p, size_t /* n */)
{
    free(p);	// 第一級配置器直接使用 free()
}

static void * reallocate(void *p, size_t /* old_sz */, size_t new_sz)
{
    void * result = realloc(p, new_sz);	// 第一級配置器直接使用 realloc()
    if (0 == result) result = oom_realloc(p, new_sz);
    return result;
}

// 以下類似 C++ 的 set_new_handler().,可以通過它指定自己的out-of-memory hander

//設定分配失敗後呼叫函式
static void (* set_malloc_handler(void (*f)()))()
{
    void (* old)() = __malloc_alloc_oom_handler;
    __malloc_alloc_oom_handler = f;
    return(old);
}

};

// malloc_alloc out-of-memory handling

#ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG
template <int inst>
void (* __malloc_alloc_template<inst>::__malloc_alloc_oom_handler)() = 0;
#endif

template <int inst>
void * __malloc_alloc_template<inst>::oom_malloc(size_t n)
{
    void (* my_malloc_handler)();
    void *result;

    for (;;) {	// 不斷嘗試釋放、配置、再釋放、再配置…
        my_malloc_handler = __malloc_alloc_oom_handler;
        if (0 == my_malloc_handler) { __THROW_BAD_ALLOC; }
        (*my_malloc_handler)();		// 呼叫處理常式,企圖釋放記憶體。
        result = malloc(n);			// 再次嘗試配置記憶體。
        if (result) return(result);
    }
}

template <int inst>
void * __malloc_alloc_template<inst>::oom_realloc(void *p, size_t n)
{
    void (* my_malloc_handler)();
    void *result;

    for (;;) {	// 不斷嘗試釋放、配置、再釋放、再配置…
        my_malloc_handler = __malloc_alloc_oom_handler;
        if (0 == my_malloc_handler) { __THROW_BAD_ALLOC; }
        (*my_malloc_handler)();	// 呼叫處理常式,企圖釋放記憶體。
        result = realloc(p, n);	// 再次嘗試配置記憶體。
        if (result) return(result);
    }
}

typedef __malloc_alloc_template<0> malloc_alloc;

4.4 第二級配置器(預設)

    第二級配置器將小於128bytes的區塊使用記憶體池(memory pool)管理【又稱層次配置(sub-allocation)】,即每次配置一大塊記憶體,並維護對應的自由連結串列(free-list),當下次有相同的記憶體需求就從free-list撥出,釋放小區塊就回收至free-list。
    避免造成太多小額區塊的記憶體碎片,第二級配置器主動將小額區塊的記憶體需求上調至8的倍數,並維護16個free-list,分別是8,16,24,32,40,48,56,64,72,80,88,96,104,112,120,128 bytes的小額區塊。
在這裡插入圖片描述
    free-lists的節點結構如下:

union obj{
	union obj* free_list_link;
	char client_data[1];
}

    可以知道節點是一個聯合體,這樣可以節省記憶體開銷——free_list_link 和client_data 用的是同一塊記憶體,前者表示指向下一個節點的指標,後者表示一個指向實際記憶體的指標:不分配的時候,節點就放在空閒連結串列裡面,節點內容是下一個節點的地址,如果被分配了,那麼節點內容就是指向一塊實際的記憶體,這樣就不用在節點裡開兩個不同記憶體的變數。

4.4.1 第二級配置器的部分實現

	 // 實際上我們應該使用 static const int x = N
	 // 來取代 enum { x = N }, 但目前支援該性質的編譯器還不多。
	 enum {__ALIGN = 8};			// 小型區塊的上調邊界,即每塊是8的倍數
	 enum {__MAX_BYTES = 128};		// 小型區塊的上限,即最大塊的大學
	 enum {__NFREELISTS = __MAX_BYTES/__ALIGN};	// free-lists 個數

// 以下是第二級配置器。
// 注意,無「template型別引數」,且第二引數完全沒派上用場。
template <bool threads, int inst>
class __default_alloc_template {

private:
  //將bytes上調至8的倍數
	 static size_t ROUND_UP(size_t bytes) {
	       return (((bytes) + __ALIGN-1) & ~(__ALIGN - 1));
	 }
__PRIVATE:
  //free-lists的節點構造
	union obj {
	       union obj * free_list_link;
	       char client_data[1];    /* The client sees this. */
	 };
private:
	//共16個free-lists
    static obj * __VOLATILE free_list[__NFREELISTS]; 
	//根據bytes大小選擇合適的第n號free-lists,n從0開始算。
    static  size_t FREELIST_INDEX(size_t bytes) {
          return (((bytes) + __ALIGN-1)/__ALIGN - 1);
  }

	 // 返回一個大小為n的物件,並可能加入大小為n的其他區塊到free-lists
	 static void *refill(size_t n);
	 // 配置一大塊空間,可以容納nobjs個大小為size的區塊
	 // 如果配置nobjs個區塊不便,nobjs可能會降低
	 static char *chunk_alloc(size_t size, int &nobjs);
	
	 // Chunk allocation state.
	 static char *start_free;//記憶體池起始位置,只在chunk_alloc()中變化
	 static char *end_free;//記憶體池結束位置,只在chunk_alloc()中變化
	 static size_t heap_size;
	
	publicstatic void *allocate(size_t n){ /* 詳述於後 */}
	static void *deallocate(void *p, size_t n){ /* 詳述於後 */}
	static void *reallocate(void *p, size_t old_sz, size_t new_sz);
};

    解釋一下(((bytes) + __ALIGN-1)/__ALIGN - 1),它其實是把要分配的記憶體大小提升一個數量級(+7,每間隔8為一個數量級),然後除以8,可以算到要找的記憶體塊下標的下一個下標,減一,剛好久找到合適的下標處,取出一塊記憶體塊。

4.4.2 allocate()

    ①由於第二級配置器是預設配置器,需先判斷區塊大小,若大於128bytes則呼叫第一級配置器。
    ②檢查對應的free-list:若有可用的區塊則直接使用,否則將區塊上調至最近8的倍數邊界,然後用refill為free-list重現填充空間。
    ③返回合適的區塊地址指標。

static void * allocate(size_t n)
{
    obj * __VOLATILE * my_free_list;
    obj * __RESTRICT result;
	//若n>128則呼叫第一級配置器
    if (n > (size_t) __MAX_BYTES) {
        return(malloc_alloc::allocate(n));
    }
    //在16個free-list中尋找合適的。
    // 通過大小取得free-list陣列下標,隨後取得對應節點的指標
    // 相當於free_list[FREELIST_INDEX(n)],存著一個未使用的記憶體塊
    my_free_list = free_list + FREELIST_INDEX(n);

    result = *my_free_list;
    if (result == 0) {
    	//沒找到可用的free-list,準備重新填充free-list
        void *r = refill(ROUND_UP(n));
        return r;
    }
    //調整free-list,將當前節點移除,並當做結果返回給使用者使用
    //free_list_link即連結串列下一塊記憶體,替代存著之前合適的數組裡
    *my_free_list = result -> free_list_link;
    return (result);
  };

在這裡插入圖片描述

4.4.3 deallocate()

    空間釋放時也和分配時相同,需要先判斷區塊大小。

 /* p may not be 0 */
  static void deallocate(void *p, size_t n)
  {
    obj *q = (obj *)p;
    obj * __VOLATILE * my_free_list;
	//大於128則呼叫第一級配置器
    if (n > (size_t) __MAX_BYTES) {
        malloc_alloc::deallocate(p, n);
        return;
    }
    //尋找對應的free-list
    my_free_list = free_list + FREELIST_INDEX(n);
	//調整free list 回收區塊,使陣列存這個記憶體塊,且這個記憶體塊指向之前陣列內的記憶體塊
    q -> free_list_link = *my_free_list;
    *my_free_list = q;
  }

在這裡插入圖片描述

4.4.4 refill() 重新填充

    之前說的allocate()中在free list沒有可用的區塊時,需要用refill()為其重新填充空間,而新的空間是通過chunk_allol()從記憶體池獲得20或小於20個新的節點。
具體看註釋。

//引數n已經上調至8的倍數
//返回大小為n的物件,且有時為free list適當的增加節點
template <bool threads, int inst>
void* __default_alloc_template<threads, inst>::refill(size_t n)
{
	int nobjs = 20;
    //呼叫chunk_alloc,嘗試獲得nobjs個大小為n的區塊作為free list的新節點
    //nobjs是引用傳入,該值會變成分配到的記憶體區塊數量
    char * chunk = chunk_alloc(n, nobjs);
    obj * __VOLATILE * my_free_list;
    obj * result;
    obj * current_obj, * next_obj;
    int i;
	//如果只獲得一個區塊,則這個區塊就分配給呼叫者用,free list無新節點
    if (1 == nobjs) return(chunk);
    //否則準備調整free list,納入新節點。
    my_free_list = free_list + FREELIST_INDEX(n);
	
	//在chunk取得的空間內建立free list
    result = (obj *)chunk;	//這塊準備返回給客端
    
	//以下引導free list指向從記憶體池新配置的空間

	//第一個大小為n的區塊需要作為refill返回值給客端,再由allocate()返回,作為已分配空間
	//故從chunk+n位置開始作為free list
    *my_free_list = next_obj = (obj *)(chunk + n);
    //剩下的交給適當的free list進行維護。
    //將free list的各個節點串接起來。
    for (i = 1; ; i++) {//i從1開始,因為第0個要返回給客端。
      current_obj = next_obj;
      next_obj = (obj *)((char *)next_obj + n);
      if (nobjs - 1 == i) 
            
           

相關推薦

STL學習筆記1空間配置 allocator

1 簡述     STL其他元件都是存放在空間配置器配置的空間中,此處空間可以是記憶體,也可以是磁碟或其他輔助儲存介質。     allocator負責記憶體的分配和釋放,以及負責物件的構造和析構,兩個操作時分開的。     每個容器都已經制定了預設的空間配置器

Struts2學習筆記1---相關配置

XML def rec 模塊 定向 -1 開發 oba 合並 Struts 2是Struts的下一代產品,是在 struts 1和WebWork的技術基礎上進行了合並的全新的Struts 2框架。 1創建action對象(三種) 1 創建普通的類,不繼承任何類,也不

SpringBoot學習筆記1配置Mybatis

target oca run class .com gpo connect auto users SpringBoot學習筆記(1):配置Mybatis 參考資料:   1.AndyLizh的博客   2.xiaolyuh123的博客 快速開始 添加Mybatis依賴(

STL原始碼剖析空間配置

歡迎大家來訪二笙的小房子,一同學習分享生活! 文章目錄 1. 寫在前面 2. SGI空間配置器 2.1 SGI標準空間配置器 2.2 SGI特殊的空間配置器,std::alloc 2.3 構造和析構基本工具 2.4 空間

cesium 學習筆記1安裝及環境配置

 cesium.js 最基本的安裝及環境配置,不同於官方教程,進一步探索官方下載包結構,瞭解node.js、伺服器、Cesium基礎包的部分內容。 相關資源  貌似用國內的網路訪問這些資源速度有點不盡人意,有條件的同學可以科學訪問,或者慢慢等也是可以噠。 安

JAVA學習筆記1——a++與++a的區別

col int 演示 opera 解析 代碼 數據 ++i div 需求:此博客用於解釋i++與++i的區別。 過程: 1、名稱解釋 ++:自增,即在原有數據基礎上+1,再賦給原有數據。 2、程序演示 (1)代碼: 1 class OperateDemo 2 { 3

vray學習筆記1

com .cn 過程 分組 是把 皮膚 mon image 基本 vray是個什麽東西? 它是個渲染器。 渲染器是個什麽東西? 渲染器就是3d軟件裏面把模型畫成一張圖片的東西,渲染的過程就是把3D物體變成2D畫面的過程。 模型是個什麽東西? 模型就是模型,它由兩部分組成,第

《深入理解C指針》學習筆記1--- 指針之外

結構 def form 學習 編程 stdlib.h struct 一個 char   C語言從誕生之初就非常善於和硬件打交道,經過這麽多年的發展之後,其靈活性和超強的特征是受到幾乎所有程序員的肯定。C語言的這種靈活性很大一部分程度來源與C指針,指針為C語言動態操控內存提供

CS231n 學習筆記1 Image CLassification

eight function 分享 便是 數據驅動 rain 分類問題 很難 特征 圖像分類是計算機視覺中的一項核心任務,那麽什麽是圖像分類? 例如,給你一個標簽集,其中包括(貓、狗、鳥、卡車、飛機...等) 然後給你一張圖片,那麽這張圖片屬於哪個類別呢?這就是一個分類

bootstrap 學習筆記1---介紹bootstrap和柵格系統

優先 cal 圖片 應用 尺寸 文件中 lin png ice   學習前端許久,對於布置框架和響應瀏覽器用html 和javascript 寫的有點繁瑣,無意間看到這個框架,覺得挺好用的就開始學習了,但是這個框架上面有很多知識,不是所有的都要學的,故將學習筆記和覺得重點的

《挑戰程序設計競賽》學習筆記 1

設計 allow 而且 硬幣 ack ket 程序設計 all 不能 2.2 貪心法 貪心法是遵循某種規則,不斷貪心選取當前最優策略的算法設計方法。 貪心法的求解思想是通過叠代地選取當前問題的局部最優解法來達成總體最優解,在叠代的過程中不斷地產生局部最優解和下一個與之前

AngularJs學習筆記1——ng-app

oot you ctrl span fun 代碼 問題 筆記 doctype 眾所周知: ng-app 指令用於告訴 AngularJS 應用當前這個元素是根元素。 所有 AngularJS 應用都必須要要一個根元素。 HTML 文檔中只允許有一個 ng-app 指令,如果

Nordic nRF52832 學習筆記1 介紹,入門,與準備工作

例程 盜版 path pdf 規範 準備 但是 依然 可能   近來,物聯網已成為大勢所趨,VR與AR正方興未艾,各種手環、遙控、智能家居也在粉墨登場。技術前沿的領航者們已經快馬加鞭,各種意誌與暗示也在上傳下達。物聯網,無線通訊,移動互聯,將成為新的目標與寵兒。最近開的電賽

javascript 高級程序設計學習筆記1

元素 新的 logs html light begin 知識 gin nbsp 知識補充: var box = document.querySelector(‘#box‘); //"beforebegin" ,在當前元素之前插入一個緊鄰的同輩元素; box.ins

Postgresql 學習筆記1

sql postgre 一、環境#配置遠程連接 su postgres vim /var/lib/pgsql/9.4/data/postgresql.conf 編輯配置文件 listen_address=’localhost’ 前面的註釋#去掉,並把’localhost’該為’*’;

spring學習筆記3——bean配置細節註意

collect 1.5 之前 ice ble person name return 引用 1. 一個bean引用另外一個bean 當Person類中有一個屬性是Car,那麽該如何配置呢 person: package com.zj.spring; public class

Hibernate學習筆記1---hibernate快速上手與準備工作

成了 -- 開源 工作 快速 tar ref orm 磁盤 持久層介紹 持久化:將內存中的數據保存在磁盤等存儲設備中。 持久化對象:指已經存儲在數據庫護著磁盤的業務對象 經典的軟件應用體系結構(三層結構) 在三層結構中,由於業務邏輯除了負責業務邏輯以外,還要負責相關的數據

jQuery源碼學習筆記1

ase tolower nodetype apt jquer 元素 bre 技術分享 停止 在慕課網上學習jQuery源碼,做一些筆記小研究。 第1章 節點遍歷 第2章 文檔處理 第3章 元素操作 第4章 樣式操作 第5章 事件體系 第6章 數據交互 第7章

linux學習筆記1

1 linux之父是linus Torvalds(李納斯 托沃滋),1991年他在赫爾辛基大學讀書時自己手動寫了一個電腦操作系統,取名linux,並且公布了源代碼。 C語言之父是Dennis M Ritchie(丹尼斯 裏奇)。 JAVA之父是詹姆斯高斯林,出生在加拿大,他編寫了多處理器版本的unix操

Node-學習筆記1

alua 就是 服務器 結果 move save toc pda 通過 什麽是Node.js 1)Node.js是一個基於Chrome V8引擎的JavaScript 運行環境 2)Node.js使用了一個事件驅動、非阻塞式I/O的模型,使其輕量又高效。 ① 事件