杂记

Rocky大约 9 分钟

top、htop命令显示的res列,

这个res展示的是操作系统看到的进程使用内存,至于进程到底有没有吧这些res内存使用完,只有进程自己知道。(甚至于res的值可以大于物理内存总量) 这也就解释了,为什么某个java进程dump出来的堆文件比如只有1G,但是res显示却大于1G,比如显示2G,3G甚至更高 如上图,htop命令显示进程4529使用了3.6G内存,但通过dump文件只有100m样子,也就是上图显示的used的大小, 而res显示的内存和上图中的total显示的内存基本一直。

dump文件会包含直接内存的信息吗?

不会 我们分配了100m的directBytebuffer,然后执行dump操作,dump文件的大小基本和used显示的大小一直,明细没有包含直接内存的信息 同理,mappedbytebuffer的内存也不会显示在dump文件中

dump文件包含了哪些内存信息?

包含的是上图中的第一个框里面的信息,可以通过mat分析dump文件后得到的size数据看,这个size的数据和第一个框的数据是吻合的

/proc/meminfo

服务器内存相关的信息

/proc/pid/maps和/proc/pid/smaps

两个大同小异,smaps 可以展示更详细的信息 这个两个文件展示的信息基本可以替代pmap命令的输出

/proc/pid/status

可以查看进程的一些统计数据,包含使用的内存等 使用的内存:VmRSS 指标 所以查看某个进行使用的内存时候,可以通过这个指标获取,而不用通过top去观察获得

gdb attach pid

注意:这个命令会阻塞整个进程,慎用 然后执行命令: dump memory dumpfilename startAddr endAddr 这个上面的dump命令,可以把进程中指定地址的内存给dump下来 这里的startAddr和endAddr可以通过上面的maps和smaps获得(前面记得加0x)

然后可以通过strings dumpfilename查看大概内容 如果指定地址空间里没有存放任何东西,那么上面的strings命令没有任何输出

strings -10 sshd.dump 查看文件中大于10个字符的信息

青年代和老年的的占比

默认是1:2,也就是默认-XX:NewRatio 的值是2 如果设置 XX:NewRatio 为4 表示 青年代和老年的的占比是1:4

青年代中survivor和eden区的占比

默认是1:8,也就是 -XX:SurvivorRatio的默认值是8 -XX:SurvivorRatio: 8Eden区与survivor大小比值

Linux系统调用mmap与munmap

mmap函数用于申请一段内存空间,我们可以将这段内存作为进程间通信的共享内存,也可以将文件直接映射到其中 munmap函数则用于释放有mmap创建的这段内存空间。

#inlcude<sys/mann.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 *start 允许用户使用某一个人特定的地址为有这段内存的起始位置。如果他被设置为NULL,则系统自动分配一个地址。
size_t length 此参数制定了内存段的长度
int prot 此参数设置内存段访问权限:
		PROT_READ:可读
		PROT_WRITE:可写
		PROT_EXEC:可执行
		PROT_NONE:内存段不能被访问
int flags 此参数控制内存段内容被修改后程序的行为。它可以被设置为以下值的按位或(MAP_SHARED和MAP_PRIVATE是互斥的,不能同时指定)
		MAP_SHARED:在进程间共享这段内存。对该内存段的修改将反应到被映射的文件中。它提供了进程间共享内存的POSIX方法
		MAP_PRIVATE:内存段调用为进程私有,对该内存段的修改不会反应到被映射的文件中
		MAP_ANONYMOUS:这段内存不是从文件映射而来的,其内容被初始化为全0,这种情况下,mmap函数的最后两个参数将被忽略
		MAP_FIXED:内存段必须位于start参数指定的地址处。start必须是内存页面大小(4096)的整数倍
		MAP_HUGETLB:按照大内存页面来分配内存空间。大内存页面的大小可以通过/pro/meminfo文件来查看
int fd 此参数是被映射文件对应的文件描述符。他一般通过open系统调用获得。
off_t offset此参数设置从文件的何处开始映射(对于不需要读入整个文件的情况)

mmap函数成功时返回指向目标内存区域的指针,失败则返回MAO_FAILED((void*)-1)并设置errno

munmap函数成功返回0.失败返回-1并设置errno
*/

Java NMT (Native Memory Tracking)

  1. 重启java进程,添加-XX:NativeMemoryTracking=detail虚拟机参数

  2. 执行jcmd 31780 VM.native_memory detail | less 查看,如下图(下图是jdk1.8的输出,jdk11的输出有些不一样,所以下面的结论要辩证看待)

  3. 通过unsafe.allocateMemory方法分配的内存会在 Internal 中体现出来,具体是 malloc 这块,System.gc()后,数据会缩小

  4. 常用的new这些方法分配的内存会在 Java Heap中提醒,具体是mmap这块,System.gc()后,数据不会缩小

mmap/malloc

操作系统针对内存分配提供了两种方式:brk和mmap

  1. brk: brk的实现是在data segment段的最高地址指针(_edata)往高位地址移动(分配的内存小于128k)
  2. mmap: mmap的实现是在memory mapping segment段找一块空闲的虚拟内存(分配的内存大于128k)

上面提到的128k,通过gperftools工具或strace命令监控发现上面128k的分界线貌似不是那么回事,目前可不用纠结,只需记得1 2的前半部分和上面的图即可

mmap除了能分配内存外,还能建立磁盘文件到虚拟内存直接的映射关系

注意 :brk和mmap分配的都是虚拟内存,并没有分配物理内存。当第一次访问分配的虚拟内存的是,发生缺页中断,这个时候操作系统才会分配物理内存,然后在页表中建立虚拟内存与物理内存直接的映射关系

  1. malloc: malloc函数封装了brk和mmap,当分配的内存小于128k的时候使用brk,反之使用mmap(这个结论辩证看待,貌似和实际不一致,可以认为没有这条)

  2. 扩展阅读: https://www.cnblogs.com/dream397/p/14629276.htmlopen in new window

为什么mmap能减少内存拷贝?

  1. 当我们使用mmap分配内存(从上面可知,这是虚拟内存),并传递相关的磁盘文件相关参数试,操作系统就会在虚拟内存中分配一块内存,并把这块内存和磁盘文件关联
  2. 当我们第一次读取这块内存的时候,发生缺页中断,操作系统会把读取磁盘文件并拷贝到物理内存(内核空间),同时也会在页表中建立虚拟内存与物理内存的映射关系。
  3. 不使用mmap的情况下,操作系统会先把磁盘文件拷贝到物理内存(内核空间),然后再把数据从物理内存(内核空间)拷贝一份到物理内存(用户空间)

看个好玩的

图中物理内存只有15.5G,但top命令显示这个java进程的res有25.1G.

目前不知道缘由,可通过如下步骤重现 多次执行上诉代码即可,上面代码中的fileName的磁盘文件大小是478m样子,没执行一次,res基本就会增加近1000m样子,(mmap500m,java程序分配byte数组500m) 再执行gc后,res会减少大概500m,减少的是java程序中byte数组的那500m,mmap的500m不会减少。 所以规律应该是: 执行n次上面代码后再执行一次gc,res会增加大概n*500m的大小(对应的就是mmap产生的内存),java程序堆的内存基本不变

cookie的domain属性

设置domain的值,前面带点和不带点的区别:

  1. 带点:任何subdomain都可以访问,包括父domain
  2. 不带点:只有完全一样的域名才能访问,subdomain不能访问(但在IE下比较特殊,它支持subdomain访问)

localStorage

  1. localStorage是无法跨域的,也无法让子域名继承父域名的localStorage数据
  2. LocalStorage是不能跨域的,但是,可以借助postMessage和iframe来实现跨域的数据读取

SSO( Single Sign On ) 单点登陆

sso的实现需要依赖cookie,虽然通过localstorage也能辗转实现,但比较麻烦,所以一般sso的实现都利用了cookie 但cookie可能遇到的问题就是:

  1. 用户禁用了cookie
  2. csrf攻击

    解决办法就是:cookie双重验证,比如后端往cookie写一个kv,uuid=xxxxx,xxxxx是一个随机值。 要求前端访问的时候需要读取cookie的中的这个uuid,并吧值放到url上或者header里,这样后端如果判断到两者数据一致,则认为请求合法 主要原理就是csrf的请求无法读取到cookie的值,只能是浏览器自动带上


系统推荐









  • 随机毒鸡汤:别说自己是单身狗,狗还可以三妻四妾。