const修饰符的使用 //const修饰变量为只读 const int a = 10; a = 20;//是错误的赋值 //指针变量 指针指向的内存 两个不同的概念 char buf[] =..."helloworld"; //从左往右看,跳过类型,看修饰那个字符 //如果是*,说明指针指向的内存不能改变 //如果是指针变量,说明指针的指向不能改变,指针的值不能修改 const char *p...是对指针指向的内存空间的内容进行封锁。 const封锁的是指针变量,不能修改其指向,但是可以修改指针指向内存当中的内容。...{ //结构体指针可以修改 //结构体指针指向的内存也可以改变 } void fun2(my_struct const *p) { //结构体指针可以修改 //如...p) { //结构体指针的指向不可以修改 //结构体指针指向内存当中的内容也不可以修改 } 如何引用其他.c文件中的const变量 extern const int a;//注意,不能再进行赋值
我们看下面这个例子,我们创建了两个子对象,一个使用的是子对象的引用,一个使用的是父对象的引用。...Paste_Image.png 按照我们已有的多态的概念,第二个应该是输出sub才对,但却输出了super。这是为什么呢?...意思就是: 在一个类中,子类中的成员变量如果和父类中的成员变量同名,那么即使他们类型不一样,只要名字一样。父类中的成员变量都会被隐藏。在子类中,父类的成员变量不能被简单的用引用来访问。...其实,简单来说,就是子类不会去重写覆盖父类的成员变量,所以成员变量的访问不能像方法一样使用多态去访问。...访问隐藏域的方法 就是使用父类的引用类型,那么就可以访问到隐藏域,就像我们例子中的代码 就是使用类型转换System.out.println(((Super)c1).s); 翻译自http://www.programcreek.com
标量和向量的区分: 元素指的是数字或者字符串(用chr表示)等,根据它可以区分两个词: 1)标量:一个元素组成的变量 2)向量:多个元素组成的变量 图片赋值就是赋予这个变量一个数值(其实也不一定是数值,...从向量中提取元素 1)根据元素位置 这里的x是刚才赋值的变量名,根据自己的情况来修改 x[4]#x第4个元素 x[-4]#排除法,除了第4个元素之外剩余的元素 x[2:4] #第2到4个元素 x[-(2...:4)]#除了第2-4个元素 x[c(1,5)]#第1个和第5个元素 2) 根据值 x[x==10]#等于10的元素 x[x<0] x[x %in% c(1,2,5)]#存在于向量c(1,2,5)中的元素...#再次使用RData时的加载命令 5)提取元素 X[x,y]#第x行第y列 X[x,]#第x行 X[,y]#第y列 -X[y] #也是第y列 X[a:b]#第a列到第b列 X[c(a,b)]#第a列和第...b列 X$列名#也可以提取列(优秀写法,而且这个命令还优秀到不用写括号的地步,并且支持Tab自动补全哦,不过只能提取一列)6)直接使用数据框中的变量!!!!!!
它会将包含变量x的连续内存块读取到缓存中。在 x86 系统上,这个块的大小是 64 字节。这意味着访问编码变量x的 4 个字节实际上最终会带来 64 个字节。...all secondary supertypes Array* _secondary_supers; 这在 Klass 类中声明了两个指针变量:_secondary_super_cache...因为这两个变量是一个接一个地声明的,所以它们会在内存中并排放置。 这两个变量在主存中是相邻的 _secondary_super_cache 本身就是一个缓存。这是一个非常小的缓存,只有一个值。...这意味着一个缓存行可以存储 8 个指针。换个说法,一个指针可以占据高速缓存行中 8 个位置中的一个。...只有一种情况两个变量不会在同一缓存行结束:当_secondary_super_cache占据位置 8,而_secondary_supers占据位置 1。
在编译时,是没有办法知道哪个 goroutine 会在 channel 上接收数据。所以编译器没法知道变量什么时候才会被释放。 2、在一个切片上存储指针或带指针的值。...一般情况下我们会这样认为:“值的拷贝是昂贵的,所以用一个指针来代替。” 但是,在很多情况下,直接的值拷贝要比使用指针廉价的多。你可能要问为什么。 1、编译器会在解除指针时做检查。...它会使得变量数据在 CPU Cache(cpu 的一级二级缓存) 中的热度更高,进而减少指令预取时 Cache 不命中的的几率。...3、在 Cache 层拷贝一堆对象,可粗略地认为和拷贝一个指针效率是一样的。CPU 在各 Cache 层和主内存中以固定大小的 cache 进行内存移动。x86 机器上是 64 字节。...减少指针的使用不仅可以降低垃圾回收的工作量,它会产生对 cache 更加友好的代码。读内存是要把数据从主内存读到 CPU 的 cache 中。
这一步做的操作就是使用ISA_MASK掩码找到isa变量中的Class并放入p16(isa是union isa_t类型,在很多系统中已经不是单纯的指向Class,还包含了内存管理等信息,所以需要用掩码来获取...二、方法缓存的数据结构基础 cache_t是方法缓存的数据结构,在objc_class中cache变量偏移64*2位: struct objc_class : objc_object { //...第二步cache_collect(false);内部会判断garbage_refs的大小,若小于32*1024什么也不做。否则会进入一个循环判断,若进程中没有缓存的访问操作才进行真正的内存释放。...可以看出,为了访问cache_t的成员变量时不加锁,付出了很大的努力,但是对于这样一个高频访问的缓存机制,这些努力都是值得的。...__SIZEOF_POINTER__),所以 64 位系统下CACHE == 64*2,根据数据结构可知这正是objc_class中cache成员变量的偏移量,而cache_t中的第一个 64 位就是
由上面一章中,我们了解了什么是RunTime,RunTime用来做什么,下面了解一下Runtime数据结构。...version:提供类的版本信息,这对于对象的序列化非常有用,它可是让我们识别出不同类定义版本中实例变量布局的改变。 info:类信息,供运行期使用的一些位标识。...cache:一个接收者对象接收到一个消息时,它会根据isa指针去查找能够响应这个消息的对象。在实际使用中,这个对象只有一部分方法是常用的,很多方法其实很少用或者根本用不上。...Paste_Image.png 从图中看出: 当我们向一个对象发送消息时,isa指针会在这个对象所属的这个类的方法列表中查找方法; 向一个类发送消息时,isa指针会在这个类的meta-class的方法列表中查找...Ivar Ivar是一种代表类中实例变量的类型。 ? Paste_Image.png ? Paste_Image.png Cache ?
还记得引言中举的例子吧,消息的执行会使用到一些编译器为实现动态语言特性而创建的数据结构和函数,Objc中的类、方法和协议等在 runtime 中都由一些数据结构来定义,这些内容在后面会讲到。...但此时获取的属性名是不带下划线的,得到属性或者变量名后我们就可以使用KVC去修改访问类中的私有属性或变量。所以OC中没有真正意义上的私有变量,私有方法也是。...方法中的隐藏参数 我们经常在方法中使用 self 关键字来引用实例本身,但从没有想过为什么 self 就能取到调用当前方法的对象吧。...实际上,它是在方法实现中访问消息接收者对象的实例变量的途径 而当方法中的 super 关键字接收到消息时,编译器会创建一个 objc_super 结构体: struct objc_super { id...当一个类被编译时,实例变量的布局也就形成了,它表明访问类的实例变量的位置。
本文包括第6章设计基于锁的并发数据结构与第7章设计无锁数据结构,后者实在有些烧脑了。...例如条款13中提过一个工厂方法: Widget* create_Widget() { ... } 如果只是返回一个裸指针,那么删除指针释放资源的责任就落在用户身上,而这常常会带来问题;如果把返回值改为shared_ptr...客户只需记住用访问器函数来得到数据,无需考虑哪些是成员函数、那些是成员变量。 2、可细微划分访问控制。...假设取消一个已存在的protected/ic成员变量,那么所有派生类中使用到它的都需相应调整;而取消一个private成员变量则无需这样。...而对于成员变量来说(首先应该是private),能访问它的函数越多,则其封装性越低。
元类中存储着类对象的类方法,当访问某个类的类方法时会通过该isa指针从元类中寻找方法对应的函数指针。...那么,属性的本质是什么?它和成员变量之间有什么区别?...具体来说,系统会在objc_ivar_list中添加一个成员变量的描述,然后在methodLists中分别添加setter和getter方法的描述。...ivars是一个数组,数组中每个元素是指向Ivar(变量信息)的指针。...具体这 objc_selector 结构体是什么取决与使用GNU的还是Apple的运行时, 在Mac OS X中SEL其实被映射为一个C字符串,可以看作是方法的名字,它并不一个指向具体方法实现(IMP类型才是
---- 为什么要使用锁? 使用多个CPU核可以带来性能的提升,如果一个应用程序运行在多个CPU核上,并且执行了系统调用,那么内核需要能够处理并行的系统调用。...当并行的访问数据结构时,例如一个核在读取数据,另一个核在写入数据,我们需要使用锁来协调对于共享数据的更新,以确保数据的一致性。 所以,我们需要锁来控制并确保共享的数据是正确的。...那这带来了一个问题,什么时候才必须要加锁呢?...可不可以在访问某个数据结构的时候,就获取所有相关联的数据结构的锁? 这是一种实现方式。...这条指令会先锁定住address,将address中的数据保存在一个临时变量中(tmp),之后将r1中的数据写入到地址中,之后再将保存在临时变量中的数据写入到r2中,最后再对于地址解锁。
Synchronized的作用主要有三个: 原子性: 确保线程互斥的访问同步代码; 可见性: 保证共享变量的修改能够及时可见,其实是通过Java内存模型中的 “对一个变量unlock操作之前,必须要同步到主内存中...;如果对一个变量进行lock操作,则将会清空工作内存中此变量的值,在执行引擎使用此变量前,需要重新从主内存中load操作或assign操作初始化变量值” 来保证的; 有序性: 有效解决重排序问题,即 “...多线程环境下线程之间如果需要共享数据,需要解决互斥访问数据的问题,监视器可以确保监视器上的数据在同一时刻只会有一个线程在访问。 什么时候需要协作?...锁消除的依据是逃逸分析的数据支持 如果不存在竞争,为什么还需要加锁呢?所以锁消除可以节省毫无意义的请求锁的时间。变量是否逃逸,对于虚拟机来说需要使用数据流分析来确定,但是对于程序员来说这还不清楚么?...所以,当一个线程访问同步块并获取锁时,会在对象头和栈帧中的锁记录里存储锁偏向的线程ID,以后该线程进入和退出同步块时不需要花费CAS操作来争夺锁资源,只需要检查是否为偏向锁、锁标识为以及ThreadID
(P201 last) 使用堆栈和/或池分配器,可以避免一些内存碎片带来的问题。堆栈分配器完全避免了内存碎片的产生。这是由于,用堆栈分配器分配到的内存块总是连续的,并且内存块必然以反向次序释放。...因此程序员要手动维护指针,在重定位时正确更新指针;另一个选择是,舍弃指针,取而代之,使用更容易重定位时修改的构件,例如智能指针(smart pointer)或句柄(handle)。...容器操作:插入、移除、顺序访问/迭代、随机访问、查找、排序。 迭代器:迭代器是一种细小的类,它“知道”如何高效地访问某类容器中的元素。...迭代器像是数组索引或指针—每次它都会指向容器中某个元素,可以移至下一个元素,并能用某方式表示是否已访问容器中所有元素。...5.5 引擎配置 读/写选项:可配置选项可简单实现为全局变量或单例中的成员变量。
objc_msgSend方法内部会访问和使用到的数据成员。...同时因为一个指针类型的变量存在着内存地址对齐的因素所以指针变量的最低3位一定是0。所以将isa中保存的内容和0xffffffff8进行与操作得到的值才是真正的对象的Class对象指针。...问题四: 既然哈希桶的数量会在运行时动态添加那么在多线程访问环境下又是如何做同步和安全处理的? 这四个问题都会在第4步中的objc_msgSend_uncached函数内部实现中找到答案。 4....因此如果处理不当就会在objc_msgSend函数的第3步中访问cache中的数据成员时发生异常。...也就是说查看是否有线程正在执行objc_entryPoints列表中的函数,如果没有则表明此时没有任何函数会访问Class对象中的cache数据,这时候就可以放心的将全局垃圾回收数组变量garbage_refs
一、内存和内存管理 ---- 1、内存:计算机的存储结构 计算机系统中有几类存储设备:cache、内存、外存。从上至下的访问速度越来越慢。...当我们使用线性分配器时,只需要在内存中维护一个指向内存特定位置的指针,如果用户程序向分配器申请内存,分配器只需要检查剩余的空闲内存、返回分配的内存区域并修改指针在内存中的位置,即移动下图中的指针: 虽然线性分配器实现为它带来了较快的执行速度以及较低的实现复杂度...同一进程下的所有线程共享相同的内存空间,它们申请内存时需要加锁,如果不加锁就存在同一块内存被2个线程同时访问的问题。 TCMalloc的做法是什么呢?...Go 语言的编译器使用逃逸分析决定哪些变量应该在栈上分配,哪些变量应该在堆上分配,其中包括使用 new、make 和字面量等方法隐式分配的内存,Go 语言的逃逸分析遵循以下两个不变性: 指向栈对象的指针不能存在于堆中...4.逃逸分析在编译阶段完成 因为无论变量的大小,只要是指针变量都会在堆上分配,所以对于小变量我们还是使用传值效率(而不是传指针)更高一点
指针:指针相当于一个变量,但是它和不同变量不一样,它存放的是其它变量在内存中的地址。...数组是根据数组的下进行访问的,多维数组在内存中是按照一维数组存储的,只是在逻辑上是多维的。 数组的存储空间,不是在静态区就是在栈上。 指针:指针很灵活,它可以指向任意类型的数据。...(指针名)都是4,在64位平台下,无论指针的类型是什么,sizeof(指针名)都是8。...使用了内存分配的函数,一旦使用完毕,要记得要使用其相应的函数释放掉。 第二:将分配的内存的指针以链表的形式自行管理,使用完毕之后从链表中删除,程序结束时可检查改链表。...但是在某些场合中,对内存区的请求不是很频繁,较高的内存访问时间也 可以接受,这是就可以分配一段线性连续,物理不连续的地址,带来的好处是一次可以分配较大块的内存。
程序具有局部性原理,也就是说进程会在某一时刻访问程序中某一固定部分的代码,这段代码中的数据我们称为热点数据,进程会高频的访问这些热点数据,那么在加载Cache的时候,就一定会加载这些热点数据,程序中不经常被访问到的数据就会暂时搁在一旁...所以,当某一个进程稳定的在CPU上运行时,CPU中的Cache缓存的都是当前进程访问的高频热点数据,那如果此时要切换线程,因为线程是进程内部的一个执行流,所以线程在切换时,Cache里面的大部分数据都是不用被更新的...验证的思路也很简单,我们在新线程中添加访问空指针指向地址的代码,看是否会影响主线程的执行!...那如果其他进程也在使用原生线程库,原生线程库中就会存在多个线程,那库中的多个线程要不要被管理起来呢?当然要!管理就得先描述,再组织,那描述出来的结构体是什么呢?...像之前所使用的join函数的第一个参数,也就是tid,他就是TCB的起始地址,也就是指向TCB结构体的指针,而线程函数的返回值实际会写到TCB结构体中的某一个字段,join函数需要tid这个地址,实际就会通过这个结构体指针从
Isa指针有两类: 1、在oc对象转化为c结构体时,用于指向对应Class结构体的isa指针; 2、在Class结构体内部实现里,isa指针作为一个成员变量,指向该class...在方法查找中,Runtime使用这个字段确定数组的索引位置; · occupied: 实际占用cache buckets的总数; · buckets: 指定Method数据结构指针的数组...3.2 方法中的隐藏参数 我们经常在方法中使用 self 关键字来引用实例本身,但从没有想过为什么 self就能取到调用当前方法的对象吧。...实际上,它是在方法实现中访问消息接收者对象的实例变量的途径。 ...最终被转换成了Ivar加入到了类的结构中,Runtime通过计算成员变量的地址偏移来寻找最终Ivar的地址,我们通过上述输出结果,可以看到 Sark的对象指针地址加上Ivar的偏移量之后刚好指向的是Test
,指向他的类对象,类对象中存放着本对象的如下信息 对象方法列表 成员变量的列表 属性列表 每个 Objective-C 对象都有相同的结构,如下图所示 | Objective-C 对象的结构图 | |...当我们发送一个消息给一个NSObject对象时,这条消息会在对象的类对象方法列表里查找 当我们发送一个消息给一个类时,这条消息会在类的Meta Class对象的方法列表里查找 objc中的类方法和实例方法有什么本质区别和联系...能否向运行时创建的类中添加实例变量?为什么?...不能向编译后得到的类中增加实例变量; 能向运行时创建的类中添加实例变量; 分析如下: 因为编译后的类已经注册在runtime中,类结构体中的objc_ivar_list 实例变量的链表和instance_size..._UNAVAILABLE; // 方法定义的链表 // 方法缓存,对象接到一个消息会根据isa指针查找消息对象, // 这时会在method Lists中遍历, // 如果cache了,常用的方法调用时就能够提高调用的效率
领取专属 10元无门槛券
手把手带您无忧上云