/*
* Copyright (c) 1996-1997
* Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Silicon Graphics makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*/ /* NOTE: This is an internal header file, included by other STL headers.
* You should not attempt to use it directly.
*/ #ifndef __SGI_STL_INTERNAL_ALLOC_H
#define __SGI_STL_INTERNAL_ALLOC_H #ifdef __SUNPRO_CC
# define __PRIVATE public
// Extra access restrictions prevent us from really making some things
// private.
#else
# define __PRIVATE private
#endif #ifdef __STL_STATIC_TEMPLATE_MEMBER_BUG
# define __USE_MALLOC
#endif //这个实现一些标准结点的内存分配管理器。这些配置器与C++标准草稿所描述的或与原始的STL所描述的都不相同。
//它们并没有封装不同的指针类型,实际上,我们假设仅存在一种指针类型。
//一些基本的函式意在分配那些不大于原始STL配置器所能分配的最大空间的个别对象独立对象。 #if 0
# include <new>
# define __THROW_BAD_ALLOC throw bad_alloc
#elif !defined(__THROW_BAD_ALLOC)
# include <iostream.h>
# define __THROW_BAD_ALLOC cerr << "out of memory" << endl; exit()
#endif #ifndef __ALLOC
# define __ALLOC alloc
#endif
#ifdef __STL_WIN32THREADS
# include <windows.h>
#endif #include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#ifndef __RESTRICT
# define __RESTRICT
#endif #if !defined(__STL_PTHREADS) && !defined(_NOTHREADS) \
&& !defined(__STL_SGI_THREADS) && !defined(__STL_WIN32THREADS)
# define _NOTHREADS
#endif # ifdef __STL_PTHREADS
// POSIX Threads
// This is dubious, since this is likely to be a high contention
// lock. Performance may not be adequate.
# include <pthread.h>
# define __NODE_ALLOCATOR_LOCK \
if (threads) pthread_mutex_lock(&__node_allocator_lock)
# define __NODE_ALLOCATOR_UNLOCK \
if (threads) pthread_mutex_unlock(&__node_allocator_lock)
# define __NODE_ALLOCATOR_THREADS true
# define __VOLATILE volatile // Needed at -O3 on SGI
# endif
# ifdef __STL_WIN32THREADS
// The lock needs to be initialized by constructing an allocator
// objects of the right type. We do that here explicitly for alloc.
# define __NODE_ALLOCATOR_LOCK \
EnterCriticalSection(&__node_allocator_lock)
# define __NODE_ALLOCATOR_UNLOCK \
LeaveCriticalSection(&__node_allocator_lock)
# define __NODE_ALLOCATOR_THREADS true
# define __VOLATILE volatile // may not be needed
# endif /* WIN32THREADS */
# ifdef __STL_SGI_THREADS
// This should work without threads, with sproc threads, or with
// pthreads. It is suboptimal in all cases.
// It is unlikely to even compile on nonSGI machines. extern "C" {
extern int __us_rsthread_malloc;
}
// The above is copied from malloc.h. Including <malloc.h>
// would be cleaner but fails with certain levels of standard
// conformance.
# define __NODE_ALLOCATOR_LOCK if (threads && __us_rsthread_malloc) \
{ __lock(&__node_allocator_lock); }
# define __NODE_ALLOCATOR_UNLOCK if (threads && __us_rsthread_malloc) \
{ __unlock(&__node_allocator_lock); }
# define __NODE_ALLOCATOR_THREADS true
# define __VOLATILE volatile // Needed at -O3 on SGI
# endif
# ifdef _NOTHREADS
// Thread-unsafe
# define __NODE_ALLOCATOR_LOCK
# define __NODE_ALLOCATOR_UNLOCK
# define __NODE_ALLOCATOR_THREADS false
# define __VOLATILE
# endif __STL_BEGIN_NAMESPACE #if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)
#pragma set woff 1174
#endif // 基于malloc的分配器通常比稍後介紹的 default alloc 速度慢,
// 一般而言是线程安全的,並且對於空間的運用比較高效。 #ifdef __STL_STATIC_TEMPLATE_MEMBER_BUG
# ifdef __DECLARE_GLOBALS_HERE
void (* __malloc_alloc_oom_handler)() = ;
// g++ 2.7.2 does not handle static template data members.
# else
extern void (* __malloc_alloc_oom_handler)();
# endif
#endif // 以下是第一级配置器。注意,没有[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 ( == result) result = oom_malloc(n);//内存分配失败,调用oom_malloc处理函数
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 ( == result) result = oom_realloc(p, new_sz);//内存分配失败,调用oom_realloc处理函数
return result;
} // 以下類似 C++ 的 set_new_handler().
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)() = ;
#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 ( == my_malloc_handler) { __THROW_BAD_ALLOC; }
(*my_malloc_handler)(); //调用函数指针指向的处理函数,企图释放记忆内存
result = malloc(n); //第一级配置器直接使用malloc系统调用
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 ( == my_malloc_handler) { __THROW_BAD_ALLOC; }
(*my_malloc_handler)();
result = realloc(p, n); //第一级配置器直接使用realloc系统调用
if (result) return(result);//直到分配内存成功
}
} typedef __malloc_alloc_template<> malloc_alloc; //简单的内存配置器,调用Alloc类型的方法进行内存申请与释放
template<class T, class Alloc>
class simple_alloc { public:
static T *allocate(size_t n)
{ return == n? : (T*) Alloc::allocate(n * sizeof (T)); }
static T *allocate(void)
{ return (T*) Alloc::allocate(sizeof (T)); }
static void deallocate(T *p, size_t n)
{ if ( != n) Alloc::deallocate(p, n * sizeof (T)); }
static void deallocate(T *p)
{ Alloc::deallocate(p, sizeof (T)); }
}; // Allocator adaptor to check size arguments for debugging.
// Reports errors using assert. Checking can be disabled with
// NDEBUG, but it's far better to just use the underlying allocator
// instead when no checking is desired.
// There is some evidence that this can confuse Purify.
template <class Alloc>
class debug_alloc { private: enum {extra = }; // Size of space used to store size. Note
// that this must be large enough to preserve
// alignment. public: static void * allocate(size_t n)
{
char *result = (char *)Alloc::allocate(n + extra);
*(size_t *)result = n;
return result + extra;
} static void deallocate(void *p, size_t n)
{
char * real_p = (char *)p - extra;
assert(*(size_t *)real_p == n);
Alloc::deallocate(real_p, n + extra);
} static void * reallocate(void *p, size_t old_sz, size_t new_sz)
{
char * real_p = (char *)p - extra;
assert(*(size_t *)real_p == old_sz);
char * result = (char *)
Alloc::reallocate(real_p, old_sz + extra, new_sz + extra);
*(size_t *)result = new_sz;
return result + extra;
} }; # ifdef __USE_MALLOC typedef malloc_alloc alloc;
typedef malloc_alloc single_client_alloc; # else // Default node allocator.
// With a reasonable compiler, this should be roughly as fast as the
// original STL class-specific allocators, but with less fragmentation.
// Default_alloc_template parameters are experimental and MAY
// DISAPPEAR in the future. Clients should just use alloc for now.
//
// Important implementation properties:
// 1. If the client request an object of size > __MAX_BYTES, the resulting
// object will be obtained directly from malloc.
// 2. In all other cases, we allocate an object of size exactly
// ROUND_UP(requested_size). Thus the client has enough size
// information that we can return the object to the proper free list
// without permanently losing part of the object.
// // The first template parameter specifies whether more than one thread
// may use this allocator. It is safe to allocate an object from
// one instance of a default_alloc and deallocate it with another
// one. This effectively transfers its ownership to the second one.
// This may have undesirable effects on reference locality.
// The second parameter is unreferenced and serves only to allow the
// creation of multiple default_alloc instances.
// Node that containers built on different allocator instances have
// different types, limiting the utility of this approach.
#ifdef __SUNPRO_CC
// breaks if we make these template class members:
enum {__ALIGN = };
enum {__MAX_BYTES = };
enum {__NFREELISTS = __MAX_BYTES/__ALIGN};
#endif template <bool threads, int inst>
class __default_alloc_template { private:
// Really we should use static const int x = N
// instead of enum { x = N }, but few compilers accept the former.
# ifndef __SUNPRO_CC
enum {__ALIGN = };
enum {__MAX_BYTES = };
enum {__NFREELISTS = __MAX_BYTES/__ALIGN};
# endif
static size_t ROUND_UP(size_t bytes) {
return (((bytes) + __ALIGN-) & ~(__ALIGN - ));
}
__PRIVATE:
union obj {
union obj * free_list_link;
char client_data[]; /* The client sees this. */
};
private:
# ifdef __SUNPRO_CC
static obj * __VOLATILE free_list[];
// Specifying a size results in duplicate def for 4.1
# else
static obj * __VOLATILE free_list[__NFREELISTS];
# endif
static size_t FREELIST_INDEX(size_t bytes) {
return (((bytes) + __ALIGN-)/__ALIGN - );
} // Returns an object of size n, and optionally adds to size n free list.
static void *refill(size_t n);
// Allocates a chunk for nobjs of size "size". nobjs may be reduced
// if it is inconvenient to allocate the requested number.
static char *chunk_alloc(size_t size, int &nobjs); // Chunk allocation state.
static char *start_free;
static char *end_free;
static size_t heap_size; # ifdef __STL_SGI_THREADS
static volatile unsigned long __node_allocator_lock;
static void __lock(volatile unsigned long *);
static inline void __unlock(volatile unsigned long *);
# endif # ifdef __STL_PTHREADS
static pthread_mutex_t __node_allocator_lock;
# endif # ifdef __STL_WIN32THREADS
static CRITICAL_SECTION __node_allocator_lock;
static bool __node_allocator_lock_initialized; public:
__default_alloc_template() {
// This assumes the first constructor is called before threads
// are started.
if (!__node_allocator_lock_initialized) {
InitializeCriticalSection(&__node_allocator_lock);
__node_allocator_lock_initialized = true;
}
}
private:
# endif class lock {
public:
lock() { __NODE_ALLOCATOR_LOCK; }
~lock() { __NODE_ALLOCATOR_UNLOCK; }
};
friend class lock; public: /* n must be > 0 */
static void * allocate(size_t n)
{
obj * __VOLATILE * my_free_list;
obj * __RESTRICT result; if (n > (size_t) __MAX_BYTES) {
return(malloc_alloc::allocate(n));
}
my_free_list = free_list + FREELIST_INDEX(n);
// Acquire the lock here with a constructor call.
// This ensures that it is released in exit or during stack
// unwinding.
# ifndef _NOTHREADS
/*REFERENCED*/
lock lock_instance;
# endif
result = *my_free_list;
if (result == ) {
void *r = refill(ROUND_UP(n));
return r;
}
*my_free_list = result -> free_list_link;
return (result);
}; /* p may not be 0 */
static void deallocate(void *p, size_t n)
{
obj *q = (obj *)p;
obj * __VOLATILE * my_free_list; if (n > (size_t) __MAX_BYTES) {
malloc_alloc::deallocate(p, n);
return;
}
my_free_list = free_list + FREELIST_INDEX(n);
// acquire lock
# ifndef _NOTHREADS
/*REFERENCED*/
lock lock_instance;
# endif /* _NOTHREADS */
q -> free_list_link = *my_free_list;
*my_free_list = q;
// lock is released here
} static void * reallocate(void *p, size_t old_sz, size_t new_sz); } ; typedef __default_alloc_template<__NODE_ALLOCATOR_THREADS, > alloc;
typedef __default_alloc_template<false, > single_client_alloc; /* We allocate memory in large chunks in order to avoid fragmenting */
/* the malloc heap too much. */
/* We assume that size is properly aligned. */
/* We hold the allocation lock. */
template <bool threads, int inst>
char*
__default_alloc_template<threads, inst>::chunk_alloc(size_t size, int& nobjs)
{
char * result;
size_t total_bytes = size * nobjs;
size_t bytes_left = end_free - start_free; if (bytes_left >= total_bytes) {
result = start_free;
start_free += total_bytes;
return(result);
} else if (bytes_left >= size) {
nobjs = bytes_left/size;
total_bytes = size * nobjs;
result = start_free;
start_free += total_bytes;
return(result);
} else {
size_t bytes_to_get = * total_bytes + ROUND_UP(heap_size >> );
// Try to make use of the left-over piece.
if (bytes_left > ) {
obj * __VOLATILE * my_free_list =
free_list + FREELIST_INDEX(bytes_left); ((obj *)start_free) -> free_list_link = *my_free_list;
*my_free_list = (obj *)start_free;
}
start_free = (char *)malloc(bytes_to_get);
if ( == start_free) {
int i;
obj * __VOLATILE * my_free_list, *p;
// Try to make do with what we have. That can't
// hurt. We do not try smaller requests, since that tends
// to result in disaster on multi-process machines.
for (i = size; i <= __MAX_BYTES; i += __ALIGN) {
my_free_list = free_list + FREELIST_INDEX(i);
p = *my_free_list;
if ( != p) {
*my_free_list = p -> free_list_link;
start_free = (char *)p;
end_free = start_free + i;
return(chunk_alloc(size, nobjs));
// Any leftover piece will eventually make it to the
// right free list.
}
}
end_free = ; // In case of exception.
start_free = (char *)malloc_alloc::allocate(bytes_to_get);
// This should either throw an
// exception or remedy the situation. Thus we assume it
// succeeded.
}
heap_size += bytes_to_get;
end_free = start_free + bytes_to_get;
return(chunk_alloc(size, nobjs));
}
} /* Returns an object of size n, and optionally adds to size n free list.*/
/* We assume that n is properly aligned. */
/* We hold the allocation lock. */
template <bool threads, int inst>
void* __default_alloc_template<threads, inst>::refill(size_t n)
{
int nobjs = ;
char * chunk = chunk_alloc(n, nobjs);
obj * __VOLATILE * my_free_list;
obj * result;
obj * current_obj, * next_obj;
int i; if ( == nobjs) return(chunk);
my_free_list = free_list + FREELIST_INDEX(n); /* Build free list in chunk */
result = (obj *)chunk;
*my_free_list = next_obj = (obj *)(chunk + n);
for (i = ; ; i++) {
current_obj = next_obj;
next_obj = (obj *)((char *)next_obj + n);
if (nobjs - == i) {
current_obj -> free_list_link = ;
break;
} else {
current_obj -> free_list_link = next_obj;
}
}
return(result);
} template <bool threads, int inst>
void*
__default_alloc_template<threads, inst>::reallocate(void *p,
size_t old_sz,
size_t new_sz)
{
void * result;
size_t copy_sz; if (old_sz > (size_t) __MAX_BYTES && new_sz > (size_t) __MAX_BYTES) {
return(realloc(p, new_sz));
}
if (ROUND_UP(old_sz) == ROUND_UP(new_sz)) return(p);
result = allocate(new_sz);
copy_sz = new_sz > old_sz? old_sz : new_sz;
memcpy(result, p, copy_sz);
deallocate(p, old_sz);
return(result);
} #ifdef __STL_PTHREADS
template <bool threads, int inst>
pthread_mutex_t
__default_alloc_template<threads, inst>::__node_allocator_lock
= PTHREAD_MUTEX_INITIALIZER;
#endif #ifdef __STL_WIN32THREADS
template <bool threads, int inst> CRITICAL_SECTION
__default_alloc_template<threads, inst>::__node_allocator_lock; template <bool threads, int inst> bool
__default_alloc_template<threads, inst>::__node_allocator_lock_initialized
= false;
#endif #ifdef __STL_SGI_THREADS
__STL_END_NAMESPACE
#include <mutex.h>
#include <time.h>
__STL_BEGIN_NAMESPACE
// Somewhat generic lock implementations. We need only test-and-set
// and some way to sleep. These should work with both SGI pthreads
// and sproc threads. They may be useful on other systems.
template <bool threads, int inst>
volatile unsigned long
__default_alloc_template<threads, inst>::__node_allocator_lock = ; #if __mips < 3 || !(defined (_ABIN32) || defined(_ABI64)) || defined(__GNUC__)
# define __test_and_set(l,v) test_and_set(l,v)
#endif template <bool threads, int inst>
void
__default_alloc_template<threads, inst>::__lock(volatile unsigned long *lock)
{
const unsigned low_spin_max = ; // spin cycles if we suspect uniprocessor
const unsigned high_spin_max = ; // spin cycles for multiprocessor
static unsigned spin_max = low_spin_max;
unsigned my_spin_max;
static unsigned last_spins = ;
unsigned my_last_spins;
static struct timespec ts = {, };
unsigned junk;
# define __ALLOC_PAUSE junk *= junk; junk *= junk; junk *= junk; junk *= junk
int i; if (!__test_and_set((unsigned long *)lock, )) {
return;
}
my_spin_max = spin_max;
my_last_spins = last_spins;
for (i = ; i < my_spin_max; i++) {
if (i < my_last_spins/ || *lock) {
__ALLOC_PAUSE;
continue;
}
if (!__test_and_set((unsigned long *)lock, )) {
// got it!
// Spinning worked. Thus we're probably not being scheduled
// against the other process with which we were contending.
// Thus it makes sense to spin longer the next time.
last_spins = i;
spin_max = high_spin_max;
return;
}
}
// We are probably being scheduled against the other process. Sleep.
spin_max = low_spin_max;
for (;;) {
if (!__test_and_set((unsigned long *)lock, )) {
return;
}
nanosleep(&ts, );
}
} template <bool threads, int inst>
inline void
__default_alloc_template<threads, inst>::__unlock(volatile unsigned long *lock)
{
# if defined(__GNUC__) && __mips >=
asm("sync");
*lock = ;
# elif __mips >= && (defined (_ABIN32) || defined(_ABI64))
__lock_release(lock);
# else
*lock = ;
// This is not sufficient on many multiprocessors, since
// writes to protected variables and the lock may be reordered.
# endif
}
#endif template <bool threads, int inst>
char *__default_alloc_template<threads, inst>::start_free = ; template <bool threads, int inst>
char *__default_alloc_template<threads, inst>::end_free = ; template <bool threads, int inst>
size_t __default_alloc_template<threads, inst>::heap_size = ; template <bool threads, int inst>
__default_alloc_template<threads, inst>::obj * __VOLATILE
__default_alloc_template<threads, inst> ::free_list[
# ifdef __SUNPRO_CC
__NFREELISTS
# else
__default_alloc_template<threads, inst>::__NFREELISTS
# endif
] = {, , , , , , , , , , , , , , , , };
// The 16 zeros are necessary to make version 4.1 of the SunPro
// compiler happy. Otherwise it appears to allocate too little
// space for the array. # ifdef __STL_WIN32THREADS
// Create one to get critical section initialized.
// We do this onece per file, but only the first constructor
// does anything.
static alloc __node_allocator_dummy_instance;
# endif #endif /* ! __USE_MALLOC */ #if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)
#pragma reset woff 1174
#endif __STL_END_NAMESPACE #undef __PRIVATE #endif /* __SGI_STL_INTERNAL_ALLOC_H */ // Local Variables:
// mode:C++
// End:

stl_alloc.h的更多相关文章

  1. 《STL源代码剖析》---stl_alloc.h阅读笔记

    这一节是讲空间的配置与释放,但不涉及对象的构造和析构,仅仅是解说对象构造前空前的申请以及对象析构后空间怎么释放. SGI版本号的STL对空间的的申请和释放做了例如以下考虑: 1.向堆申请空间 2.考虑 ...

  2. stl_alloc.h分配器

    五.分配器:5.1.头文件: 5.1.1.include<stl_alloc.h> //内存的分配. 5.1.2.include<stl_construct.h> //对象的构 ...

  3. 自己动手实现STL 01:内存配置器的实现(stl_alloc.h)

    一.前言 在STL中,容器是其中的重中之重,基本的STL中的算法,仿函数等都是围绕着容器实现的功能.而,内存配置器,是容器的实现的基础.所以,我第一次要去编写便是内存配置器的实现.在STL中,内存配置 ...

  4. STL stl_alloc.h

    # // Comment By: 凝霜 # // E-mail: mdl2009@vip.qq.com # // Blog: http://blog.csdn.net/mdl13412 # # // ...

  5. STL源代码剖析 容器 stl_hashtable.h

    本文为senlie原创.转载请保留此地址:http://blog.csdn.net/zhengsenlie hashtable ------------------------------------ ...

  6. stl_vector.h

    stl_vector.h // Filename: stl_vector.h // Comment By: 凝霜 // E-mail: mdl2009@vip.qq.com // Blog: http ...

  7. stl_list.h

    stl_list.h // Filename: stl_list.h // Comment By: 凝霜 // E-mail: mdl2009@vip.qq.com // Blog: http://b ...

  8. stl_deque.h

    stl_deque.h // Filename: stl_deque.h // Comment By: 凝霜 // E-mail: mdl2009@vip.qq.com // Blog: http:/ ...

  9. stl_tree.h

    stl_tree.h G++ ,cygnus\cygwin-b20\include\g++\stl_tree.h 完整列表 /* * * Copyright (c) 1996,1997 * Silic ...

随机推荐

  1. 面试后 follow up letter 分享

    分享一下最近面试外企的follow up letter. Dear Mr. Xu,     Thank you again for the time you and Mr. Guo spent wit ...

  2. ThinkPHP接入支付宝支付功能

    最近做系统,需要实现在线支付功能,毫不犹豫,选择的是支付宝的接口支付功能.这里我用的是即时到帐的接口,具体实现的步骤如下: 一.下载支付宝接口包 下载地址:https://b.alipay.com/o ...

  3. magento站点还原到本地

    问题描述 首先将网站文件夹解压到xampp/htdocs/wenjianjia目录下,然后替换sql文件里的域名为localhost/wenjianjia.然后访问前台,正常.访问后台,出问题了 Ma ...

  4. Laravel框架——自己写的类找不到

    composer.json my model files are stored in directory of app\models, therefor "autoload": { ...

  5. 关于html5

    html5   是用来  将 js  和 css  结合起来 从而实现 各种功能 javascript 用来定义 html5   页面的逻辑 css 来定义 html5 中的显示样式

  6. 【MySQL】囧,mysql忘记用户密码

    Ubuntu(12.04)中安装的mysql,忘记记录用户名密码了,不想重装,有木有重设密码的方法? 有位园友给出了解决方法,在mysql 5.6.23上验证没有问题. 详情用力戳这里! 1.结束当前 ...

  7. Js Framework

    http://www.mhtml5.com/2012/06/5119.html http://www.mhtml5.com/2012/06/5118.html http://cubiq.org/isc ...

  8. 【转】SharePoint 2013 stand alone服务器安装

    原文地址:http://www.cnblogs.com/jianyus/archive/2013/02/01/2889653.html  介绍:文章就是SharePoint2013安装过程的图解,包括 ...

  9. android如何获取默认的桌面程序

    [方法1] http://stackoverflow.com/questions/12594192/remove-activity-as-default-launcher/12594332#12594 ...

  10. Git批量修改提交历史

    有些时候我们可能需要批量修改提交历史,当然了,最近一次的提交历史很简单我们可以利用 git commit --amend 来进行最近一次提交的修改,如果你此时想要更新作者提交时间等也可以在amend之 ...