内存碎片

关于redis中SDS简单动态字符串

旧时模样 提交于 2020-01-25 04:55:00
1、SDS 定义 在C语言中,字符串是以’\0’字符结尾(NULL结束符)的字符数组来存储的,通常表达为字符指针的形式(char *)。它不允许字节0出现在字符串中间,因此,它不能用来存储任意的二进制数据。 sds的类型定义 typedef char *sds; 肯定有人感到困惑了,竟然sds就等同于char *? sds和传统的C语言字符串保持类型兼容,因此它们的类型定义是一样的,都是char *,在有些情况下,需要传入一个C语言字符串的地方,也确实可以传入一个sds。 但是sds和char *并不等同,sds是Binary Safe的,它可以存储任意二进制数据,不能像C语言字符串那样以字符’\0’来标识字符串的结束,因此它必然有个长度字段,这个字段在header中 sds的header结构 /* Note: sdshdr5 is never used, we just access the flags byte directly. * However is here to document the layout of type 5 SDS strings. */ struct __attribute__ ((__packed__)) sdshdr5 { unsigned char flags; /* 3 lsb of type, and 5 msb of string

数据结构之链表

雨燕双飞 提交于 2020-01-25 04:46:34
数据需要一块连续的内存空间来存储,对内存的要求比较高。而链表恰恰相反,它并不需要一块连续的内存空间,它通过“ 指针 ”将一组 零散 的内存块串联起来使用。 最常见的链表:单链表、双链表、和循环链表。 单链表 结点 :除了存储数据之外,还要记录链上的下一个节点的地址,如下图,我们把这个记录下个结点地址的指针叫作 后继指针 next 头结点 :用来记录链表的基地址。 尾结点 :指向一个空地址 NULL 针对链表的插入和删除操作,只需考虑相邻结点的指针改变,所以对应的时间复杂度是O(1)。 链表想要随机访问第k个元素,就没有数组那么高效,链表的数据并非连续存储的,所以无法像数组那样,根据首地址和下标通过寻址公式就能直接计算出对应的内存地址,而是要根据指针一个结点一个结点的一次遍历,直到找到相应的结点。需要 O(n)时间复杂度 。 循环链表 是一种特殊的单链表。它和单链表唯一的区别就在尾结点。循环链表的 尾结点指针是指向链表的头结点 。 当处理的数据具有环形结构特点时,就特别适合采用循环链表。 双向链表 双向链表支持双向遍历,它需要额外的两个空间来存储后继结点和前驱结点的地址。 时空替换思想 :“用空间换时间” 与 “用时间换空间” 当内存空间充足的时候,如果我们更加追求代码的执行速度,我们就可以选择空间复杂度相对较高,时间复杂度小相对较低的算法和数据结构,缓存就是空间换时间的例子

Redis---SDS(简单动态字符串)

喜欢而已 提交于 2020-01-25 04:46:17
   Redis 没有直接使用 C 语言传统的字符串表示(以空字符结尾的字符数组,以下简称 C 字符串), 而是自己构建了一种名为简单动态字符串(simple dynamic string,SDS)的抽象类型, 并将 SDS 用作 Redis 的默认字符串表示。   在 Redis 里面, C 字符串只会作为字符串字面量(string literal), 用在一些无须对字符串值进行修改的地方, 比如打印日志.   当 Redis 需要的不仅仅是一个字符串字面量, 而是一个可以被修改的字符串值时, Redis 就会使用 SDS 来表示字符串值 1.SDS的定义 struct sdshdr { // 记录 buf 数组中已使用字节的数量, 不包括 '\0' 的长度 // 等于 SDS 所保存字符串的长度 int len; // 记录 buf 数组中未使用字节的数量 int free; // 字节数组,用于保存字符串 char buf[]; };   buf [ ] 除了保存字符串的字符外, 还会在末尾保存一个 空字符 '\0' , 空字符不计算在 len 属性之中.   遵循空字符结尾的好处是可以重用一部分C字符串的函数. 2.SDS与C字符串的区别 2.1 常数复杂度获取字符串长度   C字符串不记录自身的长度信息, 获取字符串长度时会遍历字节数组, 直到遇到空字符为止. 复杂度为

GC垃圾回收(四个算法)

不羁岁月 提交于 2020-01-24 14:57:37
GC垃圾回收的地方: 堆+方法区 GC是什么: 分代垃圾回收算法 频繁收集新生代 较少收集老年代 基本不动元空间 JVM在进行GC时,并非每次都对上面三个内存区域一起回收的,大部分时候回收的都是指新生代。 因此GC按照回收的区域又分了两种类型,一种是普通GC(minor GC),一种是全局GC(major GC or Full GC) Minor GC和Full GC的区别 普通GC(minor GC): 只针对新生代区域的GC,指发生在新生代的垃圾收集动作,因为大多数Java对象存活率都不高,所以Minor GC非常频繁,一般回收速度也比较快。 全局GC(major GC or Full GC) :指发生在老年代的垃圾收集动作,出现了Major GC,经常会伴随至少一次的Minor GC(但并不是绝对的)。Major GC的速度一般要比Minor GC慢上10倍以上 四种GC垃圾回收算法 1.标记回收算法(已经不使用了): 2.复制算法(使用在新生代): HotSpot JVM把年轻代分为了三部分:1个Eden区和2个Survivor区(分别叫from和to)。默认比例为8:1:1,一般情况下,新创建的对象都会被分配到Eden区(一些大对象特殊处理),这些对象经过第一次Minor GC后,如果仍然存活,将会被移到Survivor区。对象在Survivor区中每熬过一次Minor

JVM堆(heap)

我的未来我决定 提交于 2020-01-24 14:12:23
概念: 一个JVM实例只存在一个堆内存,堆内存的大小是可以调节的。类加载器读取了类文件后,需要把类、方法、常变量放到堆内存中,保存所有引用类型的真实信息,以方便执行器执行,堆内存分为三部分: 一个JVM实例只存在一个堆内存,堆内存的大小是可以调节的。类加载器读取了类文件后,需要把类、方法、常变量放到堆内存中,保存所有引用类型的真实信息,以方便执行器执行。 java7堆内存逻辑上分为三部分: 新生+养老+永久 java8堆内存逻辑上分为三部分: 新生+养老+元空间 (java7之前的图) 新生区 新生区是类的诞生、成长、消亡的区域,一个类在这里产生,应用,最后被垃圾回收器收集,结束生命。新生区又分为两部分: 伊甸区(Eden space)和幸存者区(Survivor pace) ,所有的类都是在伊甸区被new出来的。幸存区有两个: 0区(Survivor 0 space)和1区(Survivor 1 space)。当伊甸园的空间用完时,程序又需要创建对象,JVM的垃圾回收器将对伊甸园区进行垃圾回收(Minor GC),将伊甸园区中的不再被其他对象所引用的对象进行销毁。然后将伊甸园中的剩余对象移动到幸存 0区。若幸存 0区也满了,再对该区进行垃圾回收,然后移动到 1 区。那如果1 区也满了呢?再移动到养老区。若养老区也满了,那么这个时候将产生MajorGC(FullGC)

【JVM】垃圾收集器以及内存分配

二次信任 提交于 2020-01-24 00:03:19
文章目录 前言 串行垃圾收集器 编写测试代码 设置垃圾回收为串行收集器 并行垃圾收集器 ParNew垃圾收集器 ParallelGC垃圾收集器 CMS垃圾收集器 测试 G1垃圾收集器(重点) 原理 Remembered Set(已记忆集合) Mixed GC 全局并发标记 拷贝存活对象 G1收集器相关参数 测试 对于G1垃圾收集器优化建议 前言 前面分享了垃圾回收的算法,还需要有具体的实现,在jvm中,实现了多种垃圾收集器,包括:串行垃圾收集器、并行垃圾收集器、CMS(并发)垃圾收集器、G1垃圾收集器,接下来,我们一个个的了解学习。 串行垃圾收集器 串行垃圾收集器,是指使用单线程进行垃圾回收,垃圾回收时,只有一个线程在工作,并且java应用中的所有线程都要暂停,等待垃圾回收的完成。这种现象称之为STW(Stop-The-World)。对于交互性较强的应用而言,这种垃圾收集器是不能够接受的。一般在Javaweb应用中是不会采用该收集器的。 编写测试代码 import java . util . ArrayList ; import java . util . List ; import java . util . Properties ; import java . util . Random ; public class TestGC { public static void

操作系统核心原理-5.内存管理(中):分页内存管理

北城余情 提交于 2020-01-23 21:24:23
   在上一篇介绍的几种多道编程的内存管理模式中,以交换内存管理最为灵活和先进。但是这种策略也存在很多重大问题,而其中最重要的两个问题就是空间浪费和程序大小受限。那么有什么办法可以解决交换内存存在的这些问题呢?答案是分页,它是我们解决交换缺陷的“不二法门”。 一、分页内存管理 1.1 解决问题之道   为了解决交换系统存在的缺陷,分页系统横空出世。分页系统的核心在于: 将虚拟内存空间和物理内存空间皆划分为大小相同的页面,如4KB、8KB或16KB等,并以页面作为内存空间的最小分配单位,一个程序的一个页面可以存放在任意一个物理页面里 。   (1)解决空间浪费碎片化问题   由于将虚拟内存空间和物理内存空间按照某种规定的大小进行分配,这里我们称之为页(Page),然后按照页进行内存分配,也就克服了外部碎片的问题。   (2)解决程序大小受限问题   程序增长有限是因为一个程序需要全部加载到内存才能运行,因此解决的办法就是使得一个程序无须全部加载就可以运行。使用分页也可以解决这个问题,只需将当前需要的页面放在内存里,其他暂时不用的页面放在磁盘上,这样一个程序同时占用内存和磁盘,其增长空间就大大增加了。而且,分页之后,如果一个程序需要更多的空间,给其分配一个新页即可(而无需将程序倒出倒进从而提高空间增长效率)。 1.2 虚拟地址的构成与地址翻译   (1)虚拟地址的构成   在分页系统下

Linux内存管理概述

a 夏天 提交于 2020-01-23 05:56:03
Linux内存管理概述 2020年悄悄的来了,新年初始正是立flag的好时候,今年的flag是总结完linux内存管理和进程管理两大模块,想法是好的,希望能坚持下去,废话到此为止,今天先来介绍linux内存管理的概述,后续内存相关文章都围绕今天的内容展开。 内存管理架构图 先上图: 用户空间 应用程序并没有直接调用系统调用申请内存,是调用glibc的库函数malloc和free申请和释放内存,malloc和free是glibc的ptmalloc分配器提供的接口,ptmalloc使用系统调用brk和mmap向内核以页为单位申请内存,然后划分成小的内存块分配给用用程序。 除了glibc的ptmalloc,还有google公司的tcmalloc和FreeBSD的jemalloc。 Note: GUN C指的是glibc,ANSI C指的是libc,是标准C库,glibc对libc做了扩展,一般只用于linux 内核空间 虚拟内存管理负责为进程分配虚拟页,内存采用延迟分配虚拟页的策略,进程第一次申请内存页时,会发生页错误异常,异常处理程序从页分配器中分配物理页,并把虚拟页和物理页的映射条目更新到页表中。 页分配器负责分配物理页,内核有多种页分配器,不连续内存页分配器、连续页分配器、引导内存分配器等。 连续内存页分配器(CMA):DMA可以不需要cpu直接控制内存,但是一般需要连续的内存

主存管理

送分小仙女□ 提交于 2020-01-22 08:38:51
1 概念 存储器 storage, memmory 能接收数据和保存数据、而且能根据命令提供这些数据的装置。 存储器分成两类: 内存储器(简称内存、主存、物理存储器) 处理机能直接访问的存储器。用来存放系统和用户的程序和数据,其特点是存取速度快,存储方式是以新换旧,断电信息丢失。 外存储器(简称外存、辅助存储器) 处理机不能直接访问的存储器。用来存放用户的各种信息,存取速度相对内存而言要慢得多,但它可用来长期保存用户信息。在文件系统中介绍。 1.内存的物理组织 物理地址: 把内存分成若干个大小相等的存储单元,每个单元给一个编号,这个编号称为内存地址(物理地址、绝对地址、实地址),存储单元占8位,称作字节(byte)。 物理地址空间: 物理地址的集合称为物理地址空间(主存地址空间),它是一个一维的线性空间。 2.程序的逻辑结构 程序地址:用户编程序时所用的地址(或称逻辑地址 、虚地址 ),基本单位可与内存的基本单位相同,也可以不相同。 程序地址空间(逻辑地址空间、虚地址空间):用户的程序地址的集合称为逻辑地址空间,它的编址总是从0开始的,可以是一维线性空间,也可以是多维空间。 2存储管理的功能 1.存储管理功能 地址映射 将程序地址空间中使用的逻辑地址变换成主存中的地址的过程 (2) 主存分配 按照一定的算法把某一空闲的主存区分配给作业或进程。 (3) 存储保护 保证用户程序

redis info all实时运行信息关注redis服务重要指标

时光总嘲笑我的痴心妄想 提交于 2020-01-22 02:02:13
(此处redis-cli命令已在linux系统下配置环境变量,可以在任何目录下直接执行,未配置的使用此命令时需在相关命令目录下执行,redis版本为4.0.1) 1、redis服务是否存活监测(ping) linux系统shell下输入:redis-cli -h IP地址 -p 端口 ping 出现pong说明redis存活。 2、客户端连接数(connected_clients) redis-cli -h IP地址 -p 端口 info Clients(或者info all,info all信息包括info Clients,以下都使用info all) | grep connected_clients得到。 这个值跟redis的服务连接池配置关系比较大,建议不要超过6000,如果太大可能是redis处理太慢。 3、拒绝连接数(rejected_connections) redis-cli -h IP地址 -p 端口 info all | grep rejected_connections 理想状态是0。如果大于0,说明创建的连接数超过了maxclients,需要排查原因。是redis连接池配置不合理还是连接这个redis实例的服务过多等。 4、阻塞客户端数量(blocked_clients) redis-cli -h IP地址 -p 端口 info all | grep