Nginx源码分析--数据对齐posix_memalign和memalign函数
posix_memalign函数()
/*
* 背景:
* 1)POSIX 1003.1d
* 2)POSIX 标明了通过malloc( ), calloc( ), 和 realloc( ) 返回的地址对于
* 任何的C类型来说都是对齐的
* 功能:由posix_memalign分配的内存空间,需要由free释放。
* 参数:
* p 分配好的内存空间的首地址
* alignment 对齐边界,Linux中,32位系统是8字节,64位系统是16字节
* size 指定分配size字节大小的内存
*
* 要求:
* 1)要求alignment是2的幂,并且是p指针大小的倍数
* 2)要求size是alignment的倍数
* 返回:
* 0 成功
* EINVAL 参数不满足要求
* ENOMEM 内存分配失败
* 注意:
* 1)该函数不影响errno,只能通过返回值判断
*
*/
memalign()函数与 posix_memalign 的不同是其将分配好的内存块首地址做为返回值
封装 posix_memalign,如果是 Solaris 则封装 memalign
#if (NGX_HAVE_POSIX_MEMALIGN)void *
ngx_memalign(size_t alignment, size_t size, ngx_log_t *log)
{void *p;int err;err = posix_memalign(&p, alignment, size);if (err) {ngx_log_error(NGX_LOG_EMERG, log, err,"posix_memalign(%uz, %uz) failed", alignment, size);p = NULL;}ngx_log_debug3(NGX_LOG_DEBUG_ALLOC, log, 0,"posix_memalign: %p:%uz @%uz", p, size, alignment);return p;
}#elif (NGX_HAVE_MEMALIGN)void *
ngx_memalign(size_t alignment, size_t size, ngx_log_t *log)
{void *p;p = memalign(alignment, size);if (p == NULL) {ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,"memalign(%uz, %uz) failed", alignment, size);}ngx_log_debug3(NGX_LOG_DEBUG_ALLOC, log, 0,"memalign: %p:%uz @%uz", p, size, alignment);return p;
}#endif
参考:Nginx源码完全注释(1)ngx_alloc.h / ngx_alloc.c
=========================
对齐
数 据的对齐(alignment)是指数据的地址和由硬件条件决定的内存块大小之间的关系。一个变量的地址是它大小的倍数的时候,这就叫做自然对齐 (naturally aligned)。例如,对于一个32bit的变量,如果它的地址是4的倍数,-- 就是说,如果地址的低两位是0,那么这就是自然对齐了。所以,如果一个类型的大小是2n个字节,那么它的地址中,至少低n位是0。对齐的规则是由硬件引起 的。一些体系的计算机在数据对齐这方面有着很严格的要求。在一些系统上,一个不对齐的数据的载入可能会引起进程的陷入。在另外一些系统,对不对齐的数据的 访问是安全的,但却会引起性能的下降。在编写可移植的代码的时候,对齐的问题是必须避免的,所有的类型都该自然对齐。
预对齐内存的分配在大多数情况下,编译器和C库透明地帮你处理对齐问题。 POSIX 标明了通过malloc( ), calloc( ), 和 realloc( ) 返回的地址对于任何的C类型来说都是对齐的。在Linux中,这些函数返回的地址在32位系统是以8字节为边界对齐,在64位系统是以16字节为边界对齐 的。有时候,对于更大的边界,例如页面,程序员需要动态的对齐。虽然动机是多种多样的,但最常见的是直接块I/O的缓存的对齐或者其它的软件对硬件的交 互,因此, POSIX 1003.1d提供一个叫做 posix_ memalign( )的函数:
/* one or the other -- either suffices */
#define _XOPEN_SOURCE 600
#define _GNU_SOURCE
#include <stdlib.h>
int posix_ memalign (void **memptr,
size_t alignment,
size_t size);
* See http://perens.com/FreeSoftware/ElectricFence/ and http://valgrind.org, respectively.
调用 posix_ memalign( )成功时会返回size字节的动态内存,并且这块内存的地址是alignment的倍数。参数alignment必须是2的幂,还是void指针的大小的倍数。返回的内存块的地址放在了memptr里面,函数返回值是0.
调用失败时,没有内存会被分配,memptr的值没有被定义,返回如下错误码之一:
EINVAL
参数不是2的幂,或者不是void指针的倍数。
ENOMEM
没有足够的内存去满足函数的请求。
要注意的是,对于这个函数,errno不会被设置,只能通过返回值得到。
由 posix_ memalign( )获得的内存通过free( )释放。用法很简单:
char *buf;
int ret;
/* allocate 1 KB along a 256-byte boundary */
ret = posix_ memalign (&buf, 256, 1024);
if (ret) {
fprintf (stderr, " posix_ memalign: %s\n",
strerror (ret));
return -1;
}
/* use 'buf'... */
free (buf);
更早的接口。在 POSIX定义了 posix_ memalign( )之前,BSD和SunOS分别提供了如下接口:
#include <malloc.h>
void * valloc (size_t size);
void * memalign (size_t boundary, size_t size);
函数valloc( )的功能和malloc( )一模一样,但返回的地址是页面对齐的。回想第四章,页面的大小很容易通过getpagesize( )得到。
相似地,函数 memalign( )是以boundary字节对齐的,而boundary必须是2的幂。在这个例子中,两个函数都返回一块足够大的内存去容纳一个ship结构,并且地址都是在一个页面的边界上:
struct ship *pirate, *hms;
pirate = valloc (sizeof (struct ship));
if (!pirate) {
perror ("valloc");
return -1;
}
hms = memalign (getpagesize ( ), sizeof (struct ship));
if (!hms) {
perror (" memalign");
free (pirate);
return -1;
}
/* use 'pirate' and 'hms'... */
free (hms);
free (pirate);
在 Linux中,由这两个函数获得的内存都可以通过free( )释放。但在别的Unix系统却未必是这样,一些系统并没有提供一个足够安全的机制去释放这些内存。考虑移植性的程序不得不放弃使用这些接口来获得动态内 存。Linux程序员最好只在考虑对老系统的兼容性时才使用它们;posix_memalign( )更加强大。只有在malloc( )不能提供足够大的对齐时,这三个接口才需要使用。
其它和对齐有关的与对齐有关的问题的范围要超过标准类型的自然对齐和动态存储器地分配。例如,非标准和复杂的类型比标准类型有更复杂的要求。另外,对对齐的关注在给指向不同类型的指针赋值和使用强转时显得加倍的重要。
非标准类型。非标准和复杂的数据类型的对齐比简单的自然对齐有着更多的要求。这里四个有很有用的方法:
•一个结构的对齐要求是和它的成员中最大的那个类型一样的。例如,一个结构中最大的是以4字节对齐的32bit的整形,那么这个结构至少以4字节对齐。
•结构也引入了填充的需要,用来保证每一个成员都符合自己的对齐要求。所以,如果一个char (可能以1字节对齐)后跟着一个int (可能以4字节对齐),编译器会自动地插入3个字节作为填充来保证int以4字节对齐。
程序员有时候排列结构里面的成员-例如,以大小来递减-来是使用作填充的垃圾空间最少。GCC的选项- Wpadded能对这些努力有帮助,因为它使得在编译器偷偷插入填充时产生警告。
•一个联合的对齐和联合里最大的类型一样。
•一个数组的对齐和数组里的元素一样。所以,数组的对齐并不比单单的一个成员严格,这样能使数组里面的所有成员都是自然对齐的。
与指针的快乐时光。因为编译器明确地处理了绝大多数的对齐问题,所以要找到潜在的错误的时候也比较困难。然而,这样的错误并不少见,特别是在处理指针和强转的时候。
一个指针指向由小的对齐强转到大的对齐的数据块,通过这个指针使用数据,能引起进程加载对于大的类型来说并没有适当对齐的数据。例如,在如下的代码片段,c到badnews的强转使得程序将c当unsigned long来读:
char greeting[] = "Ahoy Matey";
char *c = greeting[1];
unsigned long badnews = *(unsigned long *) c;
一 个unsigned long 可能以4或8字节为边界对齐;当然c只以1字节为边界对齐。明显,强转之后,c的加载,会违反对齐规则。在不同的系统中,这样可能引起的后果,小者是性能 的打击,大者是整个程序的崩溃。在能发现而不能处理对齐错误的机器结构中,内核向出问题的进程发送SIGBUS信号来终结进程。我们会在第九章讨论信号。
这种错误在现实中的普遍程度超出我们的想象,现实世界的例子虽看上去没有这么愚蠢,但亦更难以觉察了。
数据段的管理Unix 系统在历史上提供过直接管理数据段的接口。然而,程序都没有直接地使用这些接口,因为malloc( )和其它的申请方法更容易使用和更加强大。我会在这里说一下这些接口来满足一下大家的好奇心,同时也给那些想实现他自己的基于堆栈的动态内存申请机制的人 一个参考:
#include <unistd.h>
int brk (void *end);
void * sbrk (intptr_t increment);
这 些功能的名字源于老学校的Unix系统,那时堆和栈还在同一个段中。堆中动态存储器的分配由数据段的底部向上生长;栈从数据段的顶部向着堆向下生长。堆和 栈的分界线叫做break或break point。在现代的系统里面,数据段存在于它自己的内存映射,我们继续用断点来标记映射的结束地址。
一个brk( )的调用设置断点(数据段的末端)的地址为end。在成功的时候,返回0。失败的时候,返回-1,并设置errno为ENOMEM。
一个sbrk( )的调用将数据段末端生长increment字节,increment可能是正数,也可能是负数。sbrk( )返回修改后的断点。所以,increment为0时得到的是现在断点的地址:
printf ("The current break point is %p\n", sbrk (0));
特意地,POSIX和C都没有定义这些函数。但几乎所有的Unix系统,都提供其中一个或全部。可移植的程序应该坚持使用基于标准的接口。
匿名存储器映射glibc 的动态存储器使用了数据段和内存映射。实现malloc( )的经典方法是将数据段分为一系列的大小为2的幂的分区,返回最小的符合要求的那个块来满足请求。释放内存就像免费的似的和标记内存一样简单了。如果临近 的分区是空闲的,他们会被合成一个更大的分区。如果断点的下面是空的,系统可以用brk( )来降低断点,使堆收缩,将内存返回给系统。
这 个算法叫做伙伴内存分配算法(buddy memory allocation scheme)。它的优势是高速和简单,但不好的地方是引入了两种碎片。内部碎片(Internal fragmentation)发生在用更大的块来满足一个分配。这样导致了内存的低使用率。当有着足够的空闲内存来满足要求但这“块”内存分布在两个不相 邻空间的时候,外部碎片(External fragmentation)就产生了。这会导致内存的低使用率(因为一块更大的不够适合的块可能被使用了),或者内存分配失败(在没有可供选择的块 时)。
更有甚者,这个算法允许一个内存的分配“钉”住另外一个,使得glibc不能向内核归还内存。想象内存中的已被分配的两个块,块A 和块B。块A刚好在断点的下面,块B刚好在A的下面,就算释放了B,glibc也不能相应的调整断点直到A被释放。在这种情况,一个长期存在的内存分配就 把另外的空闲空间“钉”住了。
但这不需太过担忧。因为glibc无论如何也不会总例行公事一成不变地将内存返回给系统。*通常来说,在每 次释放后堆并不收缩。相反,glibc为后续的分配保留着些自由的空间。只有在堆与已分配的空间相比明显太大的时候,glibc才会把堆缩小。然而,一个 更大的分配,就能防止这个收缩了。
*glibc也使用比这伙伴系统更加先进的存储分配算法,叫做arena algorithm.
因 此,对于较大的分配,glibc并不使用堆。glibc使用一个匿名存储器映射(anonymous memory mapping)来满足请求。匿名存储器映射和在第四章讨论的基于文件的映射是相似的,只是它并不基于文件-所以为之“匿名”。实际上,匿名存储器映射是 一个简单的全0填充的大内存块,随时可供你使用。因为这种映射的存储不是基于堆的,所以并不会在数据段内产生碎片。
通过匿名映射来分配内存又下列好处:
•无需关心碎片。当程序不再需要这块内存的时候,只是撤销映射,这块内存就直接归还给系统了。
•匿名存储器映射能改变大小,有着改变大小的能力,还能像普通的映射一样接收命令(看第四章)。
•每个分配存在于独立的内存映射。没有必要再去管理一个全局的堆了。
下面是两个使用匿名存储器映射而不使用堆的劣处:
•每个存储器映射都是页面大小的整数倍。所以,如果大小不是页面整数倍的分配会浪费大量的空间。这些空间更值得忧虑,因为相对于被分配的空间,被浪费掉的空间往往更多。
•建立一个存储器映射比将堆里面的空间回收利用的负载更大,因为堆可能并不包含有任何的内核动作。越小的分配,这个劣处就明显。
跟 变戏法似的,glibc的malloc( ) 能用用数据段来满足小的分配,用存储器映射来满足大的分配。临界点是可被设定的(看后面的高级内存分配),也有可能一个glibc版本是这样,另外一个就 不是了。目前,临界点一般是128KB:比128KB小的分配由堆实现,相应地,更大的由匿名存储器映射来实现。
创建匿名存储器映射可能你会想强制在堆上使用存储器映射来满足一个特定的内存分配,也可能你会想写一个自己的存储分配系统,总之你可能会要手动创建你自己的匿名内存映射,Linux让这变得很简单。回想第四章系统调用,用来创建存储器映射的mmap( )和取消映射的munmap( ):
#include <sys/mman.h>
void * mmap (void *start,
size_t length,
int prot,
int flags,
int fd,
off_t offset);
int munmap (void *start, size_t length);
因为没有文件需要打开和管理,创建匿名存储器映射真的要比创建基于文件的存储器映射简单。两者最关键的差别在于匿名标记是否出现。让我们来看看这个例子:
void *p;
p = mmap (NULL, /* do not care where */
512 * 1024, /* 512 KB */
PROT_READ | PROT_WRITE, /* read/write */
MAP_ANONYMOUS | MAP_PRIVATE, /* anonymous, private */
-1, /* fd (ignored) */
0); /* offset (ignored) */
if (p == MAP_FAILED)
perror ("mmap");
else
/* 'p' points at 512 KB of anonymous memory... */
对于大多数的匿名映射来说,mmap( )的参数都跟这个例子一样,当然了,程序员决定的映射大小这个参数是个例外。别的参数一般都像这样:
•第一个参数是start,被设为NULL,意味着匿名映射可以内核安排的在任意地址上发生。当然给定一个non-NULL值也是有可能的,那样的话它的么地址是页对齐的,但这样会限制了可移植性。实际上很少有程序真正在意映射到哪个地址上去!
•prot参数经常都同时设置了PROT_READ和PROT_WRITE位,使得映射是可读可写的。一块不能读写的空存储器映射是没有用的。另外一方面,很少将可执行代码映射到匿名映射,因为那样做能产生潜在的安全漏洞。
•flags参数设置MAP_ANONYMOUS位,来使得映射是匿名的,设置MAP_PRIVATE位,使得映射是私有的。
•假如MAP_ANONYMOUS被设置了,fd和offset参数将被忽略的。然而,在一些更早的系统里,需要让fd为-1,如果要考虑移植性,像例子那样做是个挺好的主意。
由 匿名映射获得的内存块,看上去和由堆获得的一样。使用匿名映射的一个好处是,那块内存交给你的时候,已经是全0的了。这种映射还没有额外的负载,因为内核 使用写时复制(copy-on-write)将内存块映射到了一个全0的页面上。所以没有必要对返回的内存块使用memset( )。说实在的,这是使用calloc( )而不是用malloc( )后跟着memset( )的一个好处:知道匿名映射是本来就全0的了,calloc( )用来满足一个不能明确是全0的映射。系统调用munmap( )释放一个匿名映射,归还已分配的内存给内核。
int ret;
/* all done with 'p', so give back the 512 KB mapping */
ret = munmap (p, 512 * 1024);
if (ret)
perror ("munmap");
想复习一下mmap( ), munmap( ),和一般的映射,请翻开第四章。
映射到/dev/zero
其 它Unix系统,就像BSD,并没有MAP_ANONYMOUS标记。作为替代,它们用一个特殊的设备文件/dev/zero实现了一个类似的解决方法。 这个设备文件提供了和匿名存储器语义上一致的实现。一个映射包含了全0的写时复制页面;所以行为上和匿名存储器一样。Linux一直有一个/dev /zero设备,可以由映射这个文件来获得全0的内存块。实际上,在引入之前MAP_ANONYMOUS,Linux的程序员就是这样做的。为了对早期的 Linux版本提供向后兼容性,或者对其他Unix系统的可移植性,程序员仍然可以将映射/dev/zero作为匿名映射的替代。这个映射其他文件的映射 是不一样的:
void *p;
int fd;
/* open /dev/zero for reading and writing */
fd = open ("/dev/zero", O_RDWR);
if (fd < 0) {
perror ("open");
return -1;
}
/* map [0,page size) of /dev/zero */
p = mmap (NULL, /* do not care where */
getpagesize ( ), /* map one page */
PROT_READ | PROT_WRITE, /* map read/write */
MAP_PRIVATE, /* private mapping */
fd, /* map /dev/zero */
0); /* no offset */
if (p == MAP_FAILED) {
perror ("mmap");
if (close (fd))
perror ("close");
return -1;
}
/* close /dev/zero, no longer needed */
if (close (fd))
perror ("close");
/* 'p' points at one page of memory, use it... */
在这种情况下映射的存储器当然也是用munmap( )来取消映射的。
这种实现引入了附加的打开和关闭文件的系统调用。所以,匿名映射是个更快的解决方法。
高级存储器分配
本章所涉及的许多存储分配操作都是为内核的参数所控制和限制的,但程序员可以修改这些参数。要这么做,可以使用mallopt( )调用:
#include <malloc.h>
int mallopt (int param, int value);
一个mallopt( )的调用将制param确定的存储管理相关的参数设为value。成功时,调用返回一个非0值;失败时,返回0.要注意的是mallopt( )不设置errno。虽然它往往都成功返回,但是别过于乐观,要好好检查返回值。
Linux目前支持param的六个值,所有都被定义在了<malloc.h>:
M_CHECK_ACTION
环境变量MALLOC_CHECK_的值(将在下一节讨论)。
系统用来满足动态存储器请求的最大存储器映射数。当映射数达到了限制,数据段将被用来满足所有的分配,知道已有的映射中的某个被取消。值为0时将禁止匿名映射用于动态存储的分配。
M_MMAP_THRESHOLD
决定该用匿名映射还是用数据段来满足存储器分配请求的临界值的大小(以字节为单位)。要注意的是,有时候系统为了慎重起见,就算是比临界值小,也有可能用匿名映射来满足动态存储器的分配。值为0时会启用匿名映射来满足所有的分配,而不再使用数据段来满足请求。
M_MXFAST
Fast bin的最大大小(以字节为单位)。Fast bins是堆中特殊的内存块,永远不和临近的内存块合并,也永远不归还给系统,以碎片的增加为代价来满足高速的内存分配。值为0时,fasy bin将不被启用。
M_TOP_PAD
为 适应数据段的大小而使用的填充(padding)的大小(以字节为单位)。无论何时,在使用brk( )来使数据段变大的时候,为了以后少点调用brk( ),glibc总会请求更多的内存。相似地,但glibc收缩数据段的时候,它会保持一些多余的内存,而不是将所有的归还给系统。这多余的部分就叫做填 充。值为0时会取消填充的使用。
Table 8-1. mallopt( ) parameters
Parameter | Origin | Default value | Valid values | Special values |
M_CHECK_ACTION | Linux-specific | 0 | 0 – 2 | |
M_GRAIN | XPG standard | Unsupported on Linux | >= 0 | |
M_KEEP | XPG standard | Unsupported on Linux | >= 0 | |
M_MMAP_MAX | Linux-specific | 64 * 1024 | >=0 | 0 disables use of mmap( ) |
M_MMAP_THRESHOLD | Linux-specific | 128 * 1024 | >=0 | 0 disables use of the heap |
M_MXFAST | XPG standard | 64 | 0 – 80 | 0 disables fast bins |
M_NLBLKS | XPG standard | Unsupported on Linux | >= 0 | |
M_TOP_PAD | Linux-specific | 0 | >=0 | 0 disables padding |
程序在使用malloc( )或其它申请动态存储分配的接口之前是不能使用mallopt()的。用法很简单:
/* use mmap( ) for all allocations over 64 KB */
ret = mallopt (M_MMAP_THRESHOLD, 64 * 1024);
if (!ret)
fprintf (stderr, "mallopt failed!\n");
===================================
memalign
在GNU系统中,malloc或realloc返回的内存块地址都是8的倍数(如果是64位系统,则为16的倍数)。如果你需要更大的粒度,请使用memalign或valloc。这些函数在头文件“stdlib.h”中声明。
在GNU库中,可以使用函数free释放memalign和valloc返回的内存块。但无法在BSD系统中使用,而且BSD系统中并未提供释放这样的内存块的途径。
函数:void * memalign (size_t boundary, size_t size)
函数memalign将分配一个由size指定大小,地址是boundary的倍数的内存块。参数boundary必须是2的幂!函数memalign可以分配较大的内存块,并且可以为返回的地址指定粒度。
函数:void * valloc (size_t size)
使用函数valloc与使用函数memalign类似,函数valloc的内部实现里,使用页的大小作为对齐长度,使用memalign来分配内存。它的实现如下所示:
void *
valloc (size_t size)
{
return memalign (getpagesize (), size);
}
相关文章:

不要一辈子靠技术生存
今天看了一篇文章,感受挺深的,人的一生不能一辈子靠技术生存,尽管你的技术能力很强.(文章转载出处忘记,有哪位朋友知道的提醒一下)一、 在中国你千万不要因为学习技术就可以换来稳定的生活和高的薪水待遇,你千万更不要认为哪些从事 市场开发,跑腿的人&am…
中国顶尖的技术社区们在一个群里,会聊什么…
* 文中表情包图片来自网络

矩阵中路径数目问题
在如下8*6的矩阵中,请计算从A移动到B一共有____种走法。要求每次只能向上或向右移动一格,并且不能经过P。 8*6的矩阵,从左下角A到右上角B,一共需要走12步,其中5步向上,7步向右,因此总的走法一共…
RANet : 分辨率自适应网络效果和性能的best trade-off | CVPR 2020
作者 | VincentLee来源 | 晓飞的算法工程笔记简介深度CNN带来了性能提升的同时也带来了过高的计算量,许多研究放在了如何进行网络加速上面,其中比较直接的是根据样本难易程度进行自动调整的自适应网络。基于对自适应网络的研究,论文提出了自适…

strcpy,memcpy和memmove区别
strcpy和memcpy都是标准C库函数,它们有下面的特点。 strcpy提供了字符串的复制。即strcpy只用于字符串复制,并且它不仅复制字符串内容之外,还会复制字符串的结束符。 已知strcpy函数的原型是:char* strcpy(char* dest, const cha…

WinForm 读写配置文件
读配置文件 方法(1) //ConfigurationManager.RefreshSection("appSettings");stringsettingValue ConfigurationManager.AppSettings.Get("setting1");读配置文件 方法(2) Configuration config ConfigurationManager.OpenExeConfiguration(ConfigurationU…

PHP 读取数据库内容并以二维数组按指定列输出实例
最新PHP 读取数据库内容并以二维数组按指定列输出实例以下是三零网为大家整理的最新PHP 读取数据库内容并以二维数组按指定列输出实例的文章,希望大家能够喜欢!<?php$host "localhost"; //主机名$user "root"; //mysql用户名$passwor…
指针的本质2-void和void*及其应用在nginx中的应用
指针本质论指针有两个属性:指向变量/对象的地址和长度。 但是指针只存储地址,长度则取决于指针的类型,编译器根据指针的类型从指针指向的地址向后寻址, 指针类型不同则寻址范围也不同,比如: int*从指定地址向后寻找4字节作为变量的存储单元&…
首次揭秘!大麦如何应对超大规模高性能选座抢票?
作者| 阿里文娱技术专家恒磊、高级开发工程师新钱出品 | AI科技大本营(ID:rgznai100)背景介绍随着现场娱乐行业的不断发展,各类演出层出不穷,越来越多的演出开启选座购票满足用 户的自主选座需求。大麦的选座不仅面向中小场馆类的…

华为交换机密码恢复
华为交换机密码恢复说明:以下方法将删除原有config文件,使设备恢复到出厂配置。在设备重启时按CtrlB进入BOOT MENU之后,Press Ctrl-B to enter Boot Menu... 5Password : 缺省为空,回车即可1. Download application file to flash…
nginx源码分析--内存对齐处理
1.nginx内存对齐主要是做2件事情: 1) 内存池的内存地址对齐; 2) 长度按照2的幂取整.因为前面结构体已经是对齐了,如果后面的内存池每一小块不是2的幂,那么后面的就不能对齐 2.通用内存对齐理论 内存对齐:数据项只能…

七喜携手AMD,摆脱英特尔“潜规则”
七喜携手AMD,摆脱英特尔“潜规则”<?xml:namespace prefix o ns "urn:schemas-microsoft-com:office:office" />最近,在PC市场随着七喜董事副总裁毛骏飙揭发英特尔制定的潜规则,“游戏规则都是英特尔制定的,全…
半小时训练亿级规模知识图谱,亚马逊AI开源知识图谱嵌入表示框架DGL-KE
出品 | AI科技大本营(ID:rgznai100) 知识图谱 (Knowledge Graph)作为一个重要的技术,在近几年里被广泛运用在了信息检索,自然语言处理,以及推荐系统等各种领域。学习知识图谱的嵌入表示 &#x…

数组的各类排序
1 package sort;2 3 /**4 * 数组的各种排序操作5 * Created by liuwei on 16/3/6.6 */7 public class MSort {8 9 /**10 * 直接插入排序11 * 外层一个循环,从第2个元素开始(下标为1),遍历后面的所有元素12 * 内层一个循环,从当前位置position i 开始,每次…
Virtualbox安装使用注意
1.VirtualBox升级到4.3以后不能打开 提示创建 COM 对象失败 应用程序将被中断 解决方案:右键VirtualBox的桌面快捷方式,选择属性,选到兼容性选项卡,勾选“以兼容模式运行这个程序”,下拉框选择Windows Server 2008 …
机器学习项目模板:ML项目的6个基本步骤
来源 | DeepHub IMBA每个机器学习项目都有自己独特的形式。对于每个项目,都可以遵循一组预定义的步骤。尽管没有严格的流程,但是可以提出一个通用模板。准备问题不仅是机器学习,任何项目的第一步都是简单地定义当前的问题。您首先需要了解背景…

ib_logfile 在数据库中有何作用?
ib_logfile 在数据库中有何作用? ib_logfile0/ib_logfile1 文件在数据库中起什么作用? 如果被删除,对数据库有何影响? ----->>>>>>>>>>> 回复 #1 mugua_xinli 的帖子 用于存放InnoDB引擎的事…

Podfile 常见语法
source URL : 指定镜像仓库的源 platform : ios, 6.0 : 指定所支持系统和最低版本 inhibit_all_warnings! :屏蔽所有warning workspace 项目空间名: 指定项目空间名 xcodeproj 工程文件名:指定xcodeproj工程文件名 …

今天学完了ccna
通过10天的学习,终于学完了NA,但是会不会呢?还是个未知数,再就也一知半解的。觉得基础知识太差了,可是看书,又觉得太长了,太多了,晚上老是停电 白天啥也看不进去。热。还是静不下心&…
攀登数据科学家和数据工程师之间的隔墙
来源 | 数据派 THU机器学习的教育和研究重点往往集中在数据科学过程的模型构建、训练、测试和优化等方面。要使这些模型投入使用,需要一套工程专长和组织结构,对于其中的标准尚不存在。有一个架构可以指导数据科学和工程团队相互协作,从而将机…

js变量以及其作用域详解
2019独角兽企业重金招聘Python工程师标准>>> 一、变量的类型 Javascript和Java、C这些语言不同,它是一种无类型、弱检测的语言。它对变量的定义并不需要声明变量类型,我们只要通过赋值的形式,可以将各种类型的数据赋值给同一个变…
在A*寻路中使用二叉堆
在A*寻路中使用二叉堆 作者:Patrick Lester(2003年4月11日更新) 译者:Panic 2005年3月28日 译者序: 这一篇文章,是“A* Pathfinding for Beginners.”,也就是我翻译的另一篇文章A*寻路初探…
“Hey Siri” 背后的黑科技大揭秘!
作者 | Vishant Batta译者 | 苏本如,责编 | 伍杏玲出品 | CSDN(ID:CSDNnews)以下是译文: 如今苹果手机可随时检测并回答“Hey Siri”命令,有人可能会想,它是不是在随时记录我们的日常生活对话呢…

[ASP.NET4之旅]Circular file references are not allowed
将ASP.NET 2.0的项目升级到ASP.NET 4后,用VS2010编译站点,某些控件出现编译错误“Circular file references are not allowed”,比如: <% Control Language"C#"ClassName"NewsRight"%>解决方法…

IOS-XMPP
一、即时通讯技术简介 即时通讯技术(IM -- Instant Messaging)支持用户在线实时交谈。如果要发送一条信息,用户需要打开一个小窗口,以便让用户及其朋友在其中输入信息并让交谈双方都看到交谈的内容有许多的IM系统,如AO…

libcurl使用
官网:http://curl.haxx.se/libcurl/c/libcurl-tutorial.html #curl-config --libs 得到 -lcurl #cc libcurl_test.c -o libcurl_test -lcurl 所有的例子:http://curl.haxx.se/libcurl/c/example.html 例子: /***********************…

RH5.4下samba共享配置实例(3)
一、基于用户名的访问控制实例: 王乾大哥写的比较详细了,我是跟着他的教程学习的,按照他的教程走一边; 要求如下: 1、创建一个公共的交换文件夹,所有人都可以写入删除,但不能删除修改其他人的文…

《评人工智能如何走向新阶段》后记(再续21)
346.中国抗疫十大黑科技(以人工智能为主力的黑科技) 摘自数邦客(2020.3.30发布) 负压救护车 人工智能机器人:如送餐机器人、消毒机器人、服务型机器人,及机器人呼叫等呼吸道病毒核配检测试剂盒…

nagios npc安装后状态为off的解决方法
1、检查ndo2db的进程是不是二个 nagios 16825 0.0 0.1 6784 396 ? Ss 19:05 0:00 /usr/local/nagios/bin/ndo2db -c /usr/l nagios 17032 0.0 0.3 6784 1268 ? S 19:09 0:00 /usr/local/nagios/bin/ndo2db -c 2、检查nagios.log日志看…