Block专辑:

本篇博客

MRC-block与ARC-block

Block详解一(底层分析)

一.Block的本质

(1)block其实是一个对象, 在存放block对象的内存区域中,也包含我们经常说的isa指针,和一些能让block正常运转的各种信息。关于isa指针,在oc中每个实例对象都会有一个isa指针,指向对象的类,其实在类里面也会有isa指针,这个指针指向该类的元类。

(2)内存分配

栈:是由编译器自动分配释放,存放函数的参数值,局部变量的值以及函数返回地址。所以我们每次调用函数,都会执行压栈操作。特点是存取效率高,存取结构连续,但是空间很小,有系统自行分配以及管理栈的地址空间。

堆:由程序员分配释放,如果程序员不释放,程序结束的时候系统会收回,我们平时涉及到内存管理基本上出自于这个区域。由malloc,alloc,copy(深拷贝),new等方法触发的效果就是在堆区进行内存分配。

静态区: 该区域其实可以细分为数据区以及BSS区。数据区存放于已经初始化好的静态变量以及全局变量,而BSS区则存放还没有初始化好的静态变量以及全局变量,由系统负责释放以及分配。

常量区:存放常量,由系统释放以及分配。

代码区(文本区): 存放函数体代码。

我们定义block的时候,其所占的内存区域是分配在栈上。如果在编写程序的时候,稍加不注意,肯能会出现问题。

  1. void (^block)();
  2. if (isSure) {
  3. block = ^{
  4. NSLog(@"blockA");
  5. };
  6. }else
  7. {
  8. block = ^{
  9. NSLog(@"blockB");
  10. };
  11. }
  12. block();

因为block的内存分配在栈上的,栈上的内存是系统管理的,如果编译器没有覆写待执行的block,程序正常,如果覆写了,程序就会崩溃。

如何解决问题:也就是我们经常看到的,修饰block的时候,用copy。让block从栈中复制到堆上,copy之后该block就成了带引用计数的对象。

  1. void (^block)();
  2. if (isSure) {
  3. block = [^{
  4. NSLog(@"blockA");
  5. } copy ];
  6. }else
  7. {
  8. block = [^{
  9. NSLog(@"blockB");
  10. } copy];
  11. }
  12. block();

这样写,代码就会安全。如果手动管理内存,用完之后可以手动将其释放。

block除了存储栈和堆上,还有一个全局的block(不会捕获变量,存放在全局的内存里面),block的内存存储区域。

block 在内存中的位置

根据Block在内存中的位置分为三种类型NSGlobalBlock,NSStackBlock, NSMallocBlock。

NSGlobalBlock:类似函数,位于text段;当我们声明一个block时,如果没有这个block没有捕获外部的变量,那么这个block就位于全局区,此时对NSGlobalBlock的retain、copy、release操作都无效,ARC与MRC均是如此。

NSStackBlock:位于栈内存,函数返回后Block将无效;平时编程的时候很少遇到位于栈区的block,为什么呢?因为在ARC环境下,当我们声明并且定义了一个block,并且没有为Block添加额外的修饰符(默认是__strong修饰符),如果该Block捕获了外部的变量,实质上是有一个从__NSStackBlock__转变到__NSMallocBlock__的过程,只不过是系统帮我们完成了copy操作,将栈区的block迁移到堆区,延长了Block的生命周期。对于栈区block而言,栈block在当函数退出的时候,该空间就会被回收。

那什么时候在ARC的环境下出现__NSStackBlock__呢?如果我们在声明一个block的时候,使用了__weak或者__unsafe__unretained的修饰符,那么系统就不会为我们做copy的操作,不会将其迁移到堆区。

NSMallocBlock:位于堆内存。们需要手动调用copy方法才可以将block迁移到堆区,而在ARC环境下,__strong修饰的(默认)block只要捕获了外部变量就会位于堆区,NSMallocBlock支持retain、release,会对其引用计数+1或 -1。

  1. 示例1:
  2.  
  3. BlkSum blk1 = ^ long (int a, int b) {
  4. return a + b;
  5. };
  6. NSLog(@"blk1 = %@", blk1);// 打印结果:blk1 = <__NSGlobalBlock__: 0x47d0>
  7.  
  8. 示例2:
  9.  
  10. int base = ;
  11. BlkSum blk2 = ^ long (int a, int b) {
  12. return base + a + b;
  13. };
  14. NSLog(@"blk2 = %@", blk2); // 打印结果:blk2 = <__NSStackBlock__: 0xbfffddf8>
  15.  
  16. 示例3:
  17.  
  18. BlkSum blk3 = [[blk2 copy] autorelease];
  19. NSLog(@"blk3 = %@", blk3); // 打印结果:blk3 = <__NSMallocBlock__: 0x902fda0>

blk1和blk2的区别在于:

blk1没有使用block以外的任何外部变量,Block不需要建立局部变量值的快照,这使得block1与一般函数没有任何区别;而blk2使用了局部变量base。

注意:在定义blk3时,局部变量base被copy到栈上,作为常量供block使用,列如下面的结果为103,而不是104

  1. int base = ;
  2. base += ;
  3. BlkSum sum = ^ long (int a, int b) {
  4. return base + a + b;
  5. };
  6. base++;
  7. printf("%ld",sum(,));

在Block内变量base是只读的,如果想在block内改变base的值,在定义base时要用__block修饰

__block int base = 50;

  1. __block int base = ;
  2. base += ;
  3. BlkSum sum = ^ long (int a, int b) {
  4. base += ;
  5. return base + a + b;
  6. };
  7. base++;
  8. printf("%ld\n",sum(,));
  9. printf("%d\n",base);

输出将是114,111;

注意:Block中使用__block修饰的变量时,将取变量此刻运行的值,而不是定义的快照。

如果将block捕获的外部变量使用static修饰或者将外部变量声明为全局变量,那么block是可以直接修改该外部变量的,因为全局变量或静态变量在内存中的地址是固定的(存放于上文中的静态区),Block在读取该变量值的时候是直接从其所在内存读出,获取到的是最新值,而不是在定义时copy的常量。

拓展:(3)中也有讲到:

局部自动变量:在block中只读。block定义时copy变量的值,在Block中作为常量使用,所以即使变量的值在block外改变,也不影响在block中的值。

举例如下:

  1. int base = ;
  2. BlkSum sum = ^ long (int a, int b) {
  3. // base++; 编译错误,只读
  4. return base + a + b;
  5. };
  6. base = ;
  7. printf("%ld\n",sum(,)); // 这里输出是103,而不是3

static 修饰变量,效果与__block一样

  1. static int base = ;
  2. BlkSum sum = ^ long (int a, int b) {
  3. base++;
  4. return base + a + b;
  5. };
  6. base = ;
  7. printf("%d\n", base);
  8. printf("%ld\n",sum(,)); // 这里输出是3,而不是103
    printf("%d\n", base);

输出结果时:0;4;1

表明Block外部对base的更新会影响Block中的base的取值,同样Block对base的更新也会影响Block外部的base值。

得出一个结论:Block变量,被__block修饰的变量称作Block变量。基本类型的Block变量等效于全局变量、或静态变量

(3)捕获变量

下面有一个问题,说明:

  1. int c = 6;
  2.  
  3. int (^addBlock) (int a) = ^(int a){
  4.  
  5. return a + c;
  6. };
  7.  
  8. int addValue = addBlock(2);// addValue = 8;
  9. }

在声明的block范围内,所以变量都可以为其捕获,也就是说,在那个范围内所有的变量,在块里面都可以使用。如果要想在外面改变变量值的话,就必须使用__block修饰。

  1. __block int add = 5;

分析:

栈里面的block:
如果该block储存在栈里面,那么该block只会在声明的作用范围内有效,作用域结束的时候,栈上的__block变量和block也会被废弃。也就是说block和捕获的变量被系统一块释放了。在栈里面的__block变量只是被block使用而已,而没有被block所持有。

堆里面的block:
当栈里面的block被Copy到堆里面的时候,__block变量也会被copy到堆里面并且会被block所持有,只有不被block持有的时候才会被释放。

全局里面block:只有不被block持有的时候才会被释放。

(4)block封装了一段代码,可以在任何时候执行;block可以作为函数参数或者函数的返回值,而其本身又可以带输入参数或者返回值;它和传统函数指针类似,但是有区别:block是inline(内联函数)的,并且默认情况下,blokc对局部变量都是只读的;block代码:是一个函数对象,是在程序运行过程中产生的,普通函数:是一段固定代码,产生于编译期。

二.Block的定义与使用

(1)完整定义如下:

returnType (^blockName)(parameterTypes) = ^returnType(parameters) {...};

举例说一下:

  1. void (^myBlock)(void);//无返回值,无参数
  2. void(^myBlock)(int,int);//无返回值,有参数
  3. NSString *(^myBlock)(NSString *name ,int age);//有返回值和参数,并且在参数类型后面加入了参数名(仅为可读性)

(2)block的变量的声明

block变量的声明格式如下:返回值类型(^block名字)(参数列表);----形参变量名称可以省略,只保留变量类型即可

  1. // 声明一个无返回值,参数为两个字符串对象,叫做aBlock的Block
  2. void(^aBlock)(NSString *x,NSString * y);
  3.  
  4. // 形参变量名称可以省略,只留有变量类型即可
  5. void(^aBlock)(NSString *, NSString *);

(3)block的定义和举例

  1. /*定义属性,block属性可以用Strong修饰,也可以用copy修饰**/
  2. @property nonatomicstrongvoid(^myBlock)();//无参无返回值
  3. @property nonatomic ,strongvoid(^myBlock)(NSString *);//带参数无返回值
  4. @property (nonatomic, strong) NSString *(^myBlock2)(NSString *); //带参数与返回值
  5.  
  6. //定义变量
  7. void (^myBlock)() = nil;//无参无返回值
  8. void (^myBlcok)(NSString *) = nil;//带参数无返回值
  9. NSString *(^myBlock)(NSString *) = nil;//带参数无返回值
  10.  
  11. block被当做方法的参数
  12. 格式:(block类型)参数名称
  13. - voidtest:(void(^)())testBlock;//无参无返回值
  14. - voidtest:(void(^)(NSString *))testBlock; //带参数无返回值
  15. - voidtest:(NSString *(^)(NSString *))testBlock;//带参数与返回值
  16.  
  17. 使用typedef定义block
  18. typedef void (^myBlock)();//以后就可以使用myBlock定义无参无返回值的
  19. typedef void (^myBlock)(NSString *) //使用myBlock1定义参数类型为NSString的block
  20. typedef (NSString *)(^myBlock)(NSString *);//使用myBlock2定义参数类型为NSString,返回值也为NSString的block
  21. //定义属性
  22. @property nonatomicstrongmyBlock testBlock
  23. //定义变量
  24. myBlock testBlock = nil;
  25. //当做参数
  26. - voidtest:(myBlocktestBlock

(3)block的赋值

格式:block =  ^返回值类型(参数列表){}

注4: 通常情况下,可以省略返回值类型,因为编译器可以从存储代码块的变量中确定返回值的类型。

  1. 没有参数没有返回值
  2. myBlock testBlock = ^void(){
  3. NSLog(@"test");
  4. };
  5.  
  6. 没有返回值,void可以省略
  7. myBlock testBlock1 = ^(){
  8. NSLog(@"test1");
  9. };
  10.  
  11. 没有参数,小括号也可以省略
  12. myBlock testBlock2 = ^{
  13. NSLog(@"test2");
  14. };
  15.  
  16. 有参数没有返回值
  17. myBlock1 testBlock = ^void(NSString *str) {
  18. NSLog(str);
  19. }
  20.  
  21. 省略void
  22. myBlock1 testBlock = ^(NSString *str) {
  23. NSLog(str);
  24. }
  25.  
  26. 有参数有返回值
  27. myBlock2 testBlock = ^NSString *(NSString *str) {
  28. NSLog(str)
  29. return @"hi";
  30. }
  31.  
  32. 有返回值时也可以省略返回值类型
  33. myBlock2 testBlock2 = ^(NSString *str) {
  34. NSLog(str)
  35. return @"hi";
  36. }

声明Block变量的同时进行赋值

  1. int(^myBlock)(int) = ^(int num){
  2. return num * ;
  3. };
  4.  
  5. // 如果没有参数列表,在赋值时参数列表可以省略
  6. void(^aVoidBlock)() = ^{
  7. NSLog(@"I am a aVoidBlock");
  8. };

Block变量的调用

  1. // 调用后控制台输出"Li Lei love Han Meimei"
  2. aBlock(@"Li Lei",@"Han Meimei");
  3.  
  4. // 调用后控制台输出"result = 63"
  5. NSLog(@"result = %d", myBlock());
  6.  
  7. // 调用后控制台输出"I am a aVoidBlock"
  8. aVoidBlock();

Block作为OC函数参数

  1. //1.定义一个形参为Block的oc函数
  2. - voiduserBlockForOC :(int (^)(int ,int ))aBlock{
  3. NSLog(@"result = %d", aBlock(,));
  4. }
  5.  
  6. //2.声明并赋值定义一个Block变量
  7. int (^addBlock)(int ,int )= ^(int x,int y){
  8. return x+ y;
  9. }
  10.  
  11. //3.以Block作为函数参数,把参数像对象一样传递
  12. [self userBlockForOC:addBlock];
  13.  
  14. //4. 将第2点和第3点合并一起,以内联定义的Block作为函数参数
  15. [self useBlockForOC:^(int x, int y){
  16. return x+y;
  17. }];

(4)block在定义时并不会执行内部的代码,只有在调用时候才会执行。下面通过两个例子:

  1. //在AViewController.h定义
  2. @property nonatomiccopyvoid (^successBlock)(NSInteger count);
  3.  
  4. //在在MyViewController.m赋值
  5. if(self.successBlock && ){
  6. self.successBlock([self.cards count]);
  7. }
  8.  
  9. //在BViewController.m中调用:
  10. AViewController *aa = [[AViewController alloc]init];
  11. //回调要如何处理
  12. aa.successBlock = ^(NSInteger count){
  13. if(count == ){
  14. //处理代码
  15. }
  16. }

再看一个例子

  1. //1.在IOABgPopView.h中
  2.  
  3. #import <UIKit/UIKit.h>
  4.  
  5. typedef void (^popCallback)();
  6.  
  7. @interface IOABgPopView : UIView
  8.  
  9. + (IOABgPopView *)show;
  10.  
  11. @property(nonatomic,copy)popCallback clickCallBack;
  12.  
  13. @end
  14.  
  15. //2.在IOABgPopView.m中
  16.  
  17. - (void)closeTap{
  18. if (self.clickCallBack) {
  19. self.clickCallBack();
  20. }
  21. }
  22.  
  23. //.调用
  24. {
  25. IOABgPopView *show = [IOABgPopView show];
  26. self.show = show;
  27. WS(weakSelf);
  28. self.show.clickCallBack = ^{
  29. [weakSelf closeTap];
  30. };
  31. }

最后一个例子:用typedef为block进行重命名

我们可以使用typedef为block进行一次重命名,方法跟为函数指针命名是一样的:
  typedef int (^sum)(int ,int);

这样我们就利用typedef定义了一个block,这个block的名字就是宿命,需要传两个参数,应该这样使用

  1. Sum mysum = ^(int a,int b){
  2. n = ;
  3. return (a + b) *n;
  4. }

使用如下

  1. typedef int (^Sum) (int, int);
  2.  
  3. int main(int argc,const charchar *argv){
  4. __block int n = ;
  5. @autoreleasepool {
  6. Sum mysum = ^(int a,int b ){
  7. n = ;
  8. return (a + b)*n;
  9. };
  10. NSLog(@"(3 + 5) * %i = %d", n, mysum(, ));
  11. }
  12. return ;
  13. }

三 提到block,无论是面试还是实际开发中,都会提到一个词语“循环引用”,首先看下面一个例子:

(1)

  1. @implementation TsetBlock
    -(id)init{
    if (self = [superinit]) {
  2. self.testStr =@"中国";
  3. self.block = ^(NSString *name, NSString *str){
  4. NSLog(@"arr:%@",self.testStr); // 编译警告:Capturing 'self' strongly in this block is likely to lead to a retain cycle
  5. };
  6. }
  7. returnself;
  8. }
  9. @end

看到这个例子,很多人都表述为“block里面使用self导致循环引用”其实这种说法是不严谨的,不一定出现“self”字眼才会引起循环引用,再比如:

  1. @implementation TsetBlock
  2.  
  3. -(id)init{
  4.  
  5. if (self = [superinit]) {
  6. self.testStr =@"中国";
  7. self.block = ^(NSString *name,NSString *str){
  8. NSLog(@"arr:%@", _testStr); // 同样出现: Capturing 'self' strongly in this block is likely to lead to a retain cycle
  9. };
  10. }
  11. returnself;
  12. }
  13. @end

可以发现block代码中没有显示self,也会出现循环引用!所以只要你在block里面用到了self所拥有的的东西!

解决方案:

在ARC下不用__block,而是用__weak为了避免出现循环引用。

1.ARC:用__week

__weaktypeof (self)  weakSelf = self; 或者

__weak someClass *weakSelf = self;

2.MRC:用__block ,__block修饰的变量在Block copy时是不会retain的,所以,也可以做到破解循环引用。
__block someClass *blockSelf = self;

Block的copy、retain、release操作

对Block不管是retain、copy、release都不会改变引用计数retainCount,retainCount始终是1;

NSGlobalBlock:retain、copy、release操作都无效;
NSStackBlock:retain、release操作无效,必须注意的是,NSStackBlock在函数返回后,Block内存将被回收。即使retain也没用。容易犯的错误是[[mutableAarry addObject:stackBlock],在函数出栈后,从mutableAarry中取到的stackBlock已经被回收,变成了野指针。正确的做法是先将stackBlock copy到堆上,然后加入数组:[mutableAarry addObject:[[stackBlock copy] autorelease]]。支持copy,copy之后生成新的NSMallocBlock类型对象。
NSMallocBlock支持retain、release,虽然retainCount始终是1,但内存管理器中仍然会增加、减少计数。copy之后不会生成新的对象,只是增加了一次引用,类似retain;
尽量不要对Block使用retain操作。

(2)block 循环引用???

因为两个对象相互持有,这样就会造成循环引用。如下图所示:

两个对象相互持有,对象A持有对象B,对象B持有对象A,相互持有,最终导致两个对象都不能释放。

1.block在主函数内体用到了self/self.变量/[self 方法]意味着block对self进行持有操作;

2.self声明了属性变量block,block用copy修饰,意味着:self对block进行持有操作,会造成循环引用。

  1. typedef void(^block)();
  2.  
  3. @property (copy, nonatomic) block myBlock; // 2
  4. @property (copy, nonatomic) NSString *blockString;
  5.  
  6. - (void)testBlock {
  7. self.myBlock = ^() {
  8. //其实注释中的代码,同样会造成循环引用
  9. NSString *localString = self.blockString; // 1
  10. //NSString *localString = _blockString;
  11. //[self doSomething];
  12. };
  13. }

解决方案:

  1. 解决方法:
  2.  
  3. __weak typeof(self) weakSelf = self;
  4. self.myBlock = ^() {
  5. NSString *localString = weakSelf.blockString;
  6. };

什么时候在block中又不需要weakSelf???不会造成循环引用???

1.大部分的GCD方法

dispatch_async(dispatch_get_main_queue(), ^{ [self doSomething]; });

因为self并没有对GCD的block进行持有,没有造成循环引用,

2.大部分的动画效果

当动画结束时,UIView 会结束持有这个 block,block 对象就会释放掉,从而 block 会释放掉对于 self 的持有。整个内存引用关系被解除

3.block并不是对象的属性/变量,而是方法的参数/临时变量

  1. - (void) doSomething {
  2. [self testWithBlock:^{
  3. [self test];
  4. }];
  5. }
  6.  
  7. - (void) testWithBlock:(void(^)())block {
  8. block();
  9. }
  10.  
  11. - (void) test {
  12. NSLog(@"test");
  13. }

这里因为block只是一个临时变量,self并没有对其持有,所以没有造成循环引用

说到了weakSelf,还有一个strongSelf???

看下面一种情况:

  1. __weak __typeof__(self) weakSelf = self;
  2. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, ), ^{
  3.  
  4. [weakSelf doSomething];
  5. [weakSelf doOtherThing];
  6.  
  7. });

在 doSomething 中,weakSelf 不会变成 nil,不过在 doSomething 执行完成,调用第二个方法 doOtherThing 的时候,weakSelf 有可能被释放,于是,strongSelf 就派上用场了:

  1. __weak __typeof__(self) weakSelf = self;
  2. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, ), ^{
  3.  
  4. __strong __typeof(self) strongSelf = weakSelf;
  5. [strongSelf doSomething];
  6. [strongSelf doOtherThing];
  7.  
  8. });

__strong确保在block内,strongSelf不会被释放

总结如下:

1.在Block内如果访问self的方法、变量、建议使用weakSef

2.在Block中需要多次访问self,则需要使用StrongSelf

最后说一下:

iOS为什么要用copy修饰:

默认情况下,block是存在栈中的,可能被随时回收,通过copy操作将其在堆中保留一份,相当于一直被强引用着,因此如果block用到self,需要将其弱化, 通过__weak或者__unsafe_unretained.

如果属性的block使用assign修饰时,当再次访问时就会出现野指针访问。

block的那些事(从懵懂到使用)的更多相关文章

  1. block的哪些事 --- 学习笔记十

    //带有自动变量值的匿名函数 //block 与 C语言函数比只有两点不同,1.没有函数名. 2.带有"^". //类似于方法,如B中的值传给A中,在B中,一. 定义 : 二. 实 ...

  2. OC中的Block的那些事

    Block封装了一段代码,可以在任何时候执行 Block可以作为函数参数或者函数的返回值,而其本身又可以带输入参数或返回值. 苹果官方建议尽量多用block.在多线程.异步任务.集合遍历.集合排序.动 ...

  3. ios高效开发二--ARC跟block那点事

    block是可以捕捉上下文的特殊代码块. block可以访问定义在block外的变量,当在block中使用时,它就会为其在作用域内的每个标量变量创建一个副本. 如果通过self拥有一个block,然后 ...

  4. 关于block 用法

    Block  Apple 在C, Objective-C, C++加上Block這個延申用法.目前只有Mac 10.6 和iOS 4有支援.Block是由一堆可執行的程式組成,也可以稱做沒有名字的Fu ...

  5. iOS 中Block以及Blocks的使用,闭包方法调用

    OC: -(void)dataWithUrl:(NSString*)string AndId:(NSInteger)id returnName:(void(^)(NSString*name))back ...

  6. objective-c block 详解 转

    Block   Apple 在C, Objective-C, C++加上Block這個延申用法.目前只有Mac 10.6 和iOS 4有支援.Block是由一堆可執行的程式組成,也可以稱做沒有名字的F ...

  7. objective-c 中代码块(blocks)

    在ios4之后,引入了代码块的特性,在gcd中会经常的用到,所以决定好好的看看代码块文档,把这块总结一下.从头开始讲解代码块. 1.声明和使用代码块 一般用^操作符声明一个块变量,并作为块的开始符.而 ...

  8. iOS即时通讯之CocoaAsyncSocket源码解析二

    原文 前言 本文承接上文:iOS即时通讯之CocoaAsyncSocket源码解析一 上文我们提到了GCDAsyncSocket的初始化,以及最终connect之前的准备工作,包括一些错误检查:本机地 ...

  9. iOS开发笔记15:地图坐标转换那些事、block引用循环/weak–strong dance、UICollectionviewLayout及瀑布流、图层混合

    1.地图坐标转换那些事 (1)投影坐标系与地理坐标系 地理坐标系使用三维球面来定义地球上的位置,单位即经纬度.但经纬度无法精确测量距离戒面积,也难以在平面地图戒计算机屏幕上显示数据.通过投影的方式可以 ...

随机推荐

  1. git初试

    在gitLab上新建一个项目,creat项目文件之后,进入到项目的路径之后,复制命令git clone ‘git@gitlab.touzila.com:xiacaixiang/gitgitTest1. ...

  2. Struts(十四):通用标签-form表单

    form标签是struts2标签中一个重要标签: 可以生成html标签,使用起来和html的form标签差不多: Strut2的form标签会生成一个table,进行自动布局: 可以对表单提交的值进行 ...

  3. 1.4 正则化 regularization

    如果你怀疑神经网络过度拟合的数据,即存在高方差的问题,那么最先想到的方法可能是正则化,另一个解决高方差的方法就是准备更多数据,但是你可能无法时时准备足够多的训练数据,或者获取更多数据的代价很高.但正则 ...

  4. [Linux]使用awk批量杀进程的命令

    碰到需要杀掉某一类进程的时候,如何批量杀掉这些进程,使用awk命令是很好的选择. ps -ef|grep aaa|grep -v grep|awk '{print "kill -9 &quo ...

  5. Hello——Java10新特性,请了解一下

    2018年3月20日,Java 10 正式发布! 相关地址: 官方地址:http://www.oracle.com/technetwork/java/javase/downloads/index.ht ...

  6. [USACO15OPEN]回文的路径Palindromic Paths 2.0版

    题目描述 农夫FJ的农场是一个N*N的正方形矩阵(2\le N\le 5002≤N≤500),每一块用一个字母作标记.比如说: ABCD BXZX CDXB WCBA 某一天,FJ从农场的左上角走到右 ...

  7. ●BZOJ 1396 识别子串

    题链: http://www.joyoi.cn/problem/tyvj-2301(非权限OI患者,苟且在joyoi...)题解: 后缀自动机,线段树 先对原串建立后缀自动机,不难发现, 会影响答案是 ...

  8. 2015 多校联赛 ——HDU5334(构造)

    Virtual Participation Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Ot ...

  9. bzoj3173[Tjoi2013]最长上升子序列 平衡树+lis

    3173: [Tjoi2013]最长上升子序列 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2253  Solved: 1136[Submit][S ...

  10. AR934X built-in switch链路检测问题及处理方法

    1 问题 在使用QSDK平台配合QCA9531方案时,碰到过2个实在无解的问题,其一:将有线口连接到其它傻瓜交换机上,然后通过无线或另一个有线口登录的设备上,执行ifconfig ethx down, ...