stack 订阅
栈(stack)在计算机科学中是限定仅在表尾进行插入或删除操作的线性表。栈是一种数据结构,它按照后进先出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据。栈是只能在某一端插入和删除的特殊线性表。用桶堆积物品,先堆进来的压在底下,随后一件一件往上堆。取走时,只能从上面一件一件取。读和取都在顶部进行,底部一般是不动的。栈就是一种类似桶堆积物品的数据结构,进行删除和插入的一端称栈顶,另一端称栈底。插入一般称为进栈,删除则称为退栈。 栈也称为后进先出表。 展开全文
栈(stack)在计算机科学中是限定仅在表尾进行插入或删除操作的线性表。栈是一种数据结构,它按照后进先出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据。栈是只能在某一端插入和删除的特殊线性表。用桶堆积物品,先堆进来的压在底下,随后一件一件往上堆。取走时,只能从上面一件一件取。读和取都在顶部进行,底部一般是不动的。栈就是一种类似桶堆积物品的数据结构,进行删除和插入的一端称栈顶,另一端称栈底。插入一般称为进栈,删除则称为退栈。 栈也称为后进先出表。
信息
性    质
计算机科学中是一种数据结构
解    释
古代用竹木条横排编成车箱的车子
外文名
Stack
中文名
其他意义
姓氏
Stack进栈算法
①若TOP≥n时,则给出溢出信息,作出错处理(进栈前首先检查栈是否已满,满则溢出;不满则作②);②置TOP=TOP+1(栈指针加1,指向进栈地址);③S(TOP)=X,结束(X为新进栈的元素);
收起全文
精华内容
下载资源
问答
  • Stack

    千次阅读 2018-03-17 16:33:04
    Stackpublic class Stack<E> extends Vector<E>Stack是Vector的子类,是一个标准的先进后出的栈。Stack有几个自己特有的方法。Modifier and TypeMethod and Descriptionbooleanempty() ...

    Stack

    • public class Stack<E>   extends Vector<E>

    Stack是Vector的子类,是一个标准的先进后出的栈。

    Stack有几个自己特有的方法。

    Modifier and TypeMethod and Description
    booleanempty()
    Tests if this stack is empty.
    Epeek()
    Looks at the object at the top of this stack without removing it from the stack.
    Epop()
    Removes the object at the top of this stack and returns that object as the value of this function.
    Epush(E item)
    Pushes an item onto the top of this stack.
    intsearch(Object o)
    Returns the 1-based position where an object is on this stack.

    1. empty()方法,判断stack是否为空,返回值为boolean类型。

    2.peek()方法,返回stack栈顶的元素,如果栈为空,则报错栈为空。

    3.pop()方法,取出栈顶的元素,并且返回该元素。

    4.push()方法,将当前元素压入栈中,int型,string型,char型均可。

    5.search()方法,寻找目标第一个出现的位置距离栈顶的距离,不存在的话返回值为-1。


    代码实现:

    import java.util.Stack;
    public class Test {
        public static void main(String[] args){
            Stack stack=new Stack();
            System.out.println("stack为空吗:"+stack.empty());
            stack.push(1);
            System.out.println("放进一个元素后stack为空吗:"+stack.empty());
            stack.push('1');
            stack.push("1");
            stack.push("aa");
            System.out.println("栈顶元素:"+stack.peek());
            System.out.println("11的位置"+stack.search("11"));
            System.out.println("aa的位置"+stack.search("aa"));
            System.out.println("string型1的位置"+stack.search("1"));
            System.out.println("字符型1的位置"+stack.search('1'));
            System.out.println("整形1的位置"+stack.search(1));
            System.out.println("拿出了"+stack.pop());
            System.out.println("拿出了"+stack.pop());
            System.out.println("拿出了"+stack.pop());
            System.out.println("拿出了"+stack.pop());
            System.out.println("stack为空吗:"+stack.empty());
        }
    }

    运行结果:

    stack为空吗:true
    放进一个元素后stack为空吗:false
    栈顶元素:aa
    11的位置-1
    aa的位置1
    string型1的位置2
    字符型1的位置3
    整形1的位置4
    拿出了aa
    拿出了1
    拿出了1
    拿出了1
    stack为空吗:true



    展开全文
  • 华为云Stack私有云解决方案充分利用云计算和大数据技术,提供资源池化、全栈云服务能力,为客户提供融合资源池、托管云、混合云等场景下的解决方案。适配各个行业客户需求,有效应对企业的业务挑战,帮助客户实现...
  • Post Processing Stack.zip

    2019-07-13 14:10:17
    Post Processing Stack,内涵demo,简单易懂,可实现辉光,虚化等等特效
  • 精通Elastic Stack.pdf

    2019-05-01 15:07:46
    精通Elastic Stack.pdf 高清PDF
  • Learning ELK Stack

    2018-03-25 16:33:19
    《Learning ELK Stack.pdf》 《Learning ELK Stack.pdf》
  • Android下各语言加callStack打印信息的示例 包括C语言, C++,Java和Kernel Space。
  • stack

    千次阅读 2020-08-18 16:54:27
    stack是一种先进后出的数据结构。stack除了最顶端元素外,没有其他办法去读取其他元素,因此stack不存在遍历行为。所以stack没有迭代器。 stack容器适配器的创建 由于 stack 适配器以模板类 stack<T,Container...

    stack是一种先进后出的数据结构。stack除了最顶端元素外,没有其他办法去读取其他元素,因此stack不存在遍历行为。所以stack没有迭代器。

    stack容器适配器的创建
    由于 stack 适配器以模板类 stack<T,Container=deque>(其中 T 为存储元素的类型,Container 表示底层容器的类型)的形式位于头文件中,并定义在 std 命名空间里。

    stack<int> values;
    
    • 上面这行代码,就成功创建了一个可存储 int 类型元素,底层采用 deque 基础容器的 stack 适配器。

    上面提到,stack<T,Container=deque> 模板类提供了 2 个参数,通过指定第二个模板类型参数,我们可以使用出 deque 容器外的其它序列式容器,只要该容器支持 empty()、size()、back()、push_back()、pop_back() 这 5 个成员函数即可。

    • 在介绍适配器时提到,序列式容器中同时包含这 5 个成员函数的,有 vector、deque 和 list 这 3 个容器。因此,stack 适配器的基础容器可以是它们 3 个中任何一个。例如,下面展示了如何定义一个使用 list 基础容器的 stack 适配器:

    std::stack<std::string, std::list<int>> values;

    • 可以用一个基础容器来初始化 stack 适配器,只要该容器的类型和 stack 底层使用的基础容器类型相同即可。例如:
    std::list<int> values {1, 2, 3};
    std::stack<int,std::list<int>> my_stack (values);

    初始化后的 my_stack 适配器中,栈顶元素为 3,而不是 1。另外在第 2 行代码中,stack 第 2 个模板参数必须显式指定为 list(必须为 int 类型,和存储类型保持一致),否则 stack 底层将默认使用 deque 容器,也就无法用 lsit 容器的内容来初始化 stack 适配器。

    •  还可以用一个 stack 适配器来初始化另一个 stack 适配器,只要它们存储的元素类型以及底层采用的基础容器类型相同即可。例如:
    std::list<int> values{ 1, 2, 3 };
    std::stack<int, std::list<int>> my_stack1(values);
    std::stack<int, std::list<int>> my_stack=my_stack1;
    //std::stack<int, std::list<int>> my_stack(my_stack1);
    

    可以看到,和使用基础容器不同,使用 stack 适配器给另一个 stack 进行初始化时,有 2 种方式,使用哪一种都可以。
    注意,第 3、4 种初始化方法中,my_stack 适配器的数据是经过拷贝得来的,也就是说,操作 my_stack 适配器,并不会对 values 容器以及 my_stack1 适配器有任何影响;反过来也是如此。

    stack容器适配器支持的成员函数

    成员函数 	功能
    empty() 	当 stack 栈中没有元素时,该成员函数返回 true;反之,返回 false。
    size() 		返回 stack 栈中存储元素的个数。
    top() 		返回一个栈顶元素的引用,类型为 T&。如果栈为空,程序会报错。
    push(const T& val) 	先复制 val,再将 val 副本压入栈顶。这是通过调用底层容器的 push_back() 函数完成的。
    push(T&& obj) 	以移动元素的方式将其压入栈顶。这是通过调用底层容器的有右值引用参数的 push_back() 函数完成的。
    pop() 		弹出栈顶元素。
    emplace(arg...) 	arg... 可以是一个参数,也可以是多个参数,但它们都只用于构造一个对象,并在栈顶直接生成该对象,作为新的栈顶元素。
    swap(stack<T> & other_stack) 	将两个 stack 适配器中的元素进行互换,需要注意的是,进行互换的 2 个 stack 适配器中存储的元素类型以及底层采用的基础容器类型,都必须相同。
    
    展开全文
  • Pro MERN Stack Full Stack Web App Development with Mongo Express React and Node.pdf Pro MERN Stack Full Stack Web App Development with Mongo Express React and Node.pdf Pro MERN Stack Full Stack Web ...
  • stack(栈)在android 中的运用:自定义了一个Activity栈管理Activity
  • CSR Harmony Wireless Software Stack百度云永久下载地址及驱动安装使用说明
  • Stack原理讲解

    千次阅读 2017-09-21 00:48:27
    1. Stack概述本节基于JDK1.8.0_60 Stack继承自Vector,可以查看Vector原理讲解 Stack是动态数组实现的List,跟ArrayList一样 Stack是线程安全的 Stack是后进先出LIFO的 源码解析:Stack源码 2. Stack总结2.1 查看...

    一. Stack概述

    本节基于JDK1.8.0_60

    1. Stack继承自Vector,可以查看Vector原理讲解
    2. Stack是动态数组实现的List,跟ArrayList一样
    3. Stack是线程安全的
    4. Stack是后进先出LIFO的
    5. 源码解析:Stack源码
      这里写图片描述

    二. Stack分析

    2.1 查看Vector原理讲解

    由于Stack继承自Vector,所以部分是跟Vector是一样的,可以直接查看我写的Vector原理讲解,这里不再重复。

    2.2 Stack存储结构

    这里写图片描述

    2.3 Stack初始化

    public Stack() {
    
    }

    Stack首次创建时,不包含任何元素

    • 执行push时(即,将元素推入栈中),是通过将元素追加的数组的末尾中。
    • 执行peek时(即,取出栈顶元素,不执行删除),是返回数组末尾的元素。
    • 执行pop时(即,取出栈顶元素,并将该元素从栈中删除),是取出数组末尾的元素,然后将该元素从数组中删除。
      这里写图片描述

    三. Stack与Deque比较

    Deque接口及其实现提供了更完整和一致的LIFO(后进先出)堆栈操作,优先使用Deque实现类,如:

    Stack.class类注释中说明:
    more complete and consistent set of LIFO stack operations is provided by the {@link Deque} interface and its implementations, which should be used in preference to this class.  For example:
     <pre>   {@code  Deque<Integer> stack = new ArrayDeque<Integer>();}</pre>
    
    Deque <Integer> stack = new ArrayDeque <Integer>()

    四. Stack后进先出操作

    package com.src.collection.list;
    
    import java.util.Stack;
    
    /**
     * Stack的LIFO操作
     * */
    public class StackTest {
    
        public static void main(String[] args) {
            Stack<Integer> stack = new Stack();
            stack.push(1);
            stack.push(2);
            stack.push(3);
            System.out.println("当前堆栈元素数组: " + stack.toString());
    
            int first = stack.pop();
            System.out.println("第一个出来的数据: " + first + ", 剩余元素个数: " + stack.size());
    
            int second = stack.pop();
            System.out.println("第二个出来的数据: " + second + ", 剩余元素个数: " + stack.size());
    
            int third = stack.pop();
            System.out.println("第三个出来的数据: " + third + ", 剩余元素个数: " + stack.size());
    
    //      stack.pop();
        }
    }

    运行结果:

    当前堆栈元素数组: [1, 2, 3]
    第一个出来的数据: 3, 剩余元素个数: 2
    第二个出来的数据: 2, 剩余元素个数: 1
    第三个出来的数据: 1, 剩余元素个数: 0

    五. Stack pop异常

    package com.src.collection.list;
    
    import java.util.Stack;
    
    /**
     * Stack的LIFO操作
     * */
    public class StackTest {
    
        public static void main(String[] args) {
            Stack<Integer> stack = new Stack();
            stack.push(1);
            stack.push(2);
            stack.push(3);
            System.out.println("当前堆栈元素数组: " + stack.toString());
    
            int first = stack.pop();
            System.out.println("第一个出来的数据: " + first + ", 剩余元素个数: " + stack.size());
    
            int second = stack.pop();
            System.out.println("第二个出来的数据: " + second + ", 剩余元素个数: " + stack.size());
    
            int third = stack.pop();
            System.out.println("第三个出来的数据: " + third + ", 剩余元素个数: " + stack.size());
    
            stack.pop();
        }
    }

    运行结果:

    当前堆栈元素数组: [1, 2, 3]
    第一个出来的数据: 3, 剩余元素个数: 2
    第二个出来的数据: 2, 剩余元素个数: 1
    第三个出来的数据: 1, 剩余元素个数: 0
    Exception in thread "main" java.util.EmptyStackException
        at java.util.Stack.peek(Stack.java:102)
        at java.util.Stack.pop(Stack.java:84)
        at com.src.collection.list.StackTest.main(StackTest.java:26)

    六. 源码

    package java.util;
    
    public class Stack<E> extends Vector<E> {
        public Stack() {}
    
        // 入栈
        public E push(E item) {
            addElement(item);
            return item;
        }
    
        // 出栈
        public synchronized E pop() {
            E       obj;
            int     len = size();
            obj = peek();
            removeElementAt(len - 1);
            return obj;
        }
    
        // 返回栈顶元素
        public synchronized E peek() {
            int     len = size();
            if (len == 0)
                throw new EmptyStackException();
            return elementAt(len - 1);
        }
    
        public boolean empty() {
            return size() == 0;
        }
    
        public synchronized int search(Object o) {
            int i = lastIndexOf(o);
    
            if (i >= 0) {
                return size() - i;
            }
            return -1;
        }
    
        private static final long serialVersionUID = 1224463164541339165L;
    }
    展开全文
  • ELKstack 中文指南

    热门讨论 2016-02-23 15:42:21
    ELKstack 中文指南,三斗大神著。 ELK Stack 在最近两年迅速崛起, 成为机器数据分析, 或者说实时日志处理领域, 开源界的 第一选择
  • Fullstack.React.The Complete Book on ReactJS and Friends .r20.2017.1.pdf
  • 头脑的智慧!前人之思想
  • StackMap属性解析

    千次阅读 2019-07-01 17:59:12
    由于我们会在后续的文章介绍class验证环节,其中在校验方法时需要使用到StackMap.那么什么是StackMap呢? 从Java 6开始,JVM规范有一个更新文档,JSR 202,里面提到一种新的字节码校验算法,“类型检查”;在此之前是...

    由于我们会在后续的文章介绍class验证环节,其中在校验方法时需要使用到StackMap.那么什么是StackMap呢?

    从Java 6开始,JVM规范有一个更新文档,JSR 202,里面提到一种新的字节码校验算法,“类型检查”;在此之前是用“类型推导”的算法。为了支持新算法,Class文件从版本50开始添加了一个新的属性表,叫做StackMapTable,里面记录的是一个方法中操作数栈与局部变量区的类型在一些特定位置的状态。

    在版本号大于或等于50.0的Class文件中,如果方法的Code属性中没有附带StackMapTable属性,那就意味着它带有一个隐式的StackMap属性。这个StackMap属性的作用等同于number_of_entries值为0的StackMapTable属性。一个方法的Code属性最多只能有一个StackMapTable属性,否则将抛出ClassFormatError异常。

    StackMapTable的格式如下:

    StackMapTable_attribute { 
     u2 attribute_name_index;  
     u4 attribute_length;  
     u2 number_of_entries;  
     stack_map_frame entries[number_of_entries]; 
    } 
    

    其中各项的含义如下:

    • attribute_name_index

      attribute_name_index项的值必须是对常量池的有效索引,常量池在该索引的项处必须是CONSTANT_Utf8_info(§4.4.7)结构,表示“StackMapTable”字符串。

    • attribute_length

      attribute_length项的值表示当前属性的长度,不包括开始的6个字节。

    • number_of_entries

      number_of_entries项的值给出了entries表中的成员数量。Entries表的每个成员是都是一个stack_map_frame结构的项。

    • entries[]

      entries表给出了当前方法所需的stack_map_frame结构。

      每个stack_map_frame结构都使用一个特定的字节偏移量来表示类型状态。每个帧类型(Frame Type)都显式或隐式地标明一个offset_delta(增量偏移量)值,用于计算每个帧在运行时的实际字节码偏移量。使用时帧的字节偏移量计算方法为:前一帧的字节码偏移量(Bytecode Offset)加上offset_delta的值再加1,如果前一个帧是方法的初始帧(Initial Frame),那这时候字节码偏移量就是offset_delta。

      **只要保证栈映射帧有正确的存储顺序,在类型检查时我们就可以使用增量偏移量而不是实际的字节码偏移量。此外,由于堆每一个帧都使用了offset_delta+1的计算方式,我们可以确保偏移量不会重复。 在Code属性的code[]数组项中,如果偏移量i的位置是某条指令的起点,同时这个Code属性包含有StackMapTable属性,它的entries项中也有一个适用于地址偏移量i的stack_map_frame结构,那我们就说这条指令拥有一个与之相对应的栈映射帧。 **

      stack_map_frame结构的第一个字节作为类型标记(Tag),第一个字节后会跟随0或多个字节用于说明更多信息,这些信息因类型标记的不同而变化。


    栈帧

    一个栈映射帧可以包含若干种帧类型(Frame Types):

    union stack_map_frame {  
        same_frame;  
        same_locals_1_stack_item_frame;  
        same_locals_1_stack_item_frame_extended;  
        chop_frame;  
        same_frame_extended;  
        append_frame;  
        full_frame;  
    }  
      
    same_frame {  
        u1 frame_type = SAME;/* 0-63 */  
    }  
      
    same_locals_1_stack_item_frame {  
        u1 frame_type = SAME_LOCALS_1_STACK_ITEM;/* 64-127 */  
        verification_type_info stack[1];  
    }  
      
    same_locals_1_stack_item_frame_extended {  
        u1 frame_type = SAME_LOCALS_1_STACK_ITEM_EXTENDED;/* 247 */  
        u2 offset_delta;  
        verification_type_info stack[1];  
    }  
      
    chop_frame {  
        u1 frame_type=CHOP; /* 248-250 */  
        u2 offset_delta;  
    }  
      
    same_frame_extended {  
        u1 frame_type = SAME_FRAME_EXTENDED;/* 251*/  
        u2 offset_delta;  
    }  
      
    append_frame {  
        u1 frame_type = APPEND; /* 252-254 */  
        u2 offset_delta;  
        verification_type_info locals[frame_type -251];  
    }  
      
    full_frame {  
        u1 frame_type = FULL_FRAME; /* 255 */  
        u2 offset_delta;  
        u2 number_of_locals;  
        verification_type_info locals[number_of_locals];  
        u2 number_of_stack_items;  
        verification_type_info stack[number_of_stack_items];  
    }  
    

    这里需要提的是,在kvm内部使用的是栈类型的数据结构为,关于这点,是本人看kvm源码总结出来.关于相关文档并没有找到:

    kvm_frame {  
        u2 offset_delta;  
        u2 number_of_locals;  
        verification_type_info locals[number_of_locals];  
        u2 number_of_stack_items;  
        verification_type_info stack[number_of_stack_items];  
    }  
    

    verification_type_info结构的第一个字节tag作为类型标记,之后跟随0至多个字节表示由tag类型所决定的信息。每个verification_type_info结构可以描述1个至2个存储单元的验证类型信息。

    union verification_type_info {         
    Top_variable_info;     
    Integer_variable_info;     
    Float_variable_info;     
    Long_variable_info;     
    Double_variable_info;      
    Null_variable_info;     
    UninitializedThis_variable_info; 
    Object_variable_info;     
    Uninitialized_variable_info; 
    } 
    
    // Top_variable_info类型说明这个局部变量拥有验证类型top(ᴛ)。
    Top_variable_info {  
    u1 tag = ITEM_Top; /* 0 */ 
    } 
    
    
    // Integer_variable_info类型说明这个局部变量包含验证类型int 
    Integer_variable_info {  
    u1 tag = ITEM_Integer; /* 1 */ 
    } 
    
    
    //Float_variable_info类型说明局部变量包含验证类型float 
    Float_variable_info {  
    u1 tag = ITEM_Float; /* 2 */ 
    } 
    
    
    // Long_variable_info结构在局部变量表或操作数栈中占用2个存储单元。 
    Long_variable_info {  
    u1 tag = ITEM_Long; /* 4 */ 
    } 
    
    
    // Double_variable_info结构在局部变量表或操作数栈中占用2个存储单元。 
    Double_variable_info {  
    u1 tag = ITEM_Double; /* 3 */  
    }
    
    // Null_variable_info类型说明存储单元包含验证类型null。
    Null_variable_info {  
    u1 tag = ITEM_Null; /* 5 */ 
    }
    
    // UninitializedThis_variable_info类型说明存储单元包含验证类型uninitializedThis。 
    UninitializedThis_variable_info {  
    u1 tag = ITEM_UninitializedThis; /* 6 */ 
    } 
    
    // Object_variable_info类型说明存储单元包含某个Class的实例。由常量池在cpool_index给出的索引处的CONSTANT_CLASS_Info(§4.4.1)结构表示。 
    Object_variable_info {  
    u1 tag = ITEM_Object; /* 7 */ 
    u2 cpool_index; 
    } 
    
    // Uninitialized_variable_info说明存储单元包含验证类型uninitialized(offset)。offset项给出了一个偏移量,表示在包含此StackMapTable属性的Code属性中,new指令创建的对象所存储的位置。
    
    Uninitialized_variable_info {  
    u1 tag = ITEM_Uninitialized /* 8 */  
    u2 offset; 
    }   
    

    基本块

    关于栈帧的形成,是在每个基本块开始的位置生成。

    一个“基本块”(basic block)就是一个方法中的代码最长的直线型一段段代码序列。“直线型”也就是说代码序列中除了末尾之外不能有控制流(跳转)指令。

    一个基本块的开头可以是方法的开头,也可以是某条跳转指令的跳转目标;
    一个基本块的结尾可以是方法的末尾,也可以是某条跳转指令(Java中就是goto、if*系列等;invoke*系列的方法调用指令不算在跳转指令中).

    如果一个方法代码如下:

    public class Foo {  
        public void foo() {  
            // basic block 1 start  
            int i = 0;  
            int j = 0;  
            if (i > 0) { // basic block 1 end  
              // basic block 2 start  
              int k = 0;  
              // basic block 2 end  
            }  
            // basic block 3 start  
            int l = 0;  
            // basic block 3 end  
        }  
    }  
    

    那么可以看到就有3个基本块。不过在Java Class文件里StackMapTable关心的是类型检查,为了进一步压缩这个表的大小,使用的基本块定义比通常的定义要更宽松些:一个条件跳转的直落分支与条件跳转前的代码算在同一个基本块内。于是前面的例子就变成:

    public class Foo {  
        public void foo() {  
            // basic block 1 start  
            int i = 0;  
            int j = 0;  
            if (i > 0) {  
              int k = 0;  
              // basic block 1 end  
            }  
            // basic block 2 start  
            int l = 0;  
            // basic block 2 end  
        }  
    }  
    

    这个方法就会有一个StackMapTable属性表,其中有一个stack frame map记录(本来应该是两个,但第一个是隐式的,不记录在属性表里)。

    public void foo();  
      Code:  
       Stack=1, Locals=4, Args_size=1  
       /* basic block 1 start */  
       0:   iconst_0  
       1:   istore_1  
       2:   iconst_0  
       3:   istore_2  
       4:   iload_1  
       5:   ifle    10  
       8:   iconst_0  
       9:   istore_3  
       /* basic block 1 end */  
       /* basic block 2 start */  
       10:  iconst_0 /* stack frame map 1 refers to here */  
       11:  istore_3  
       12:  return  
       /* basic block 2 end */  
      
      LocalVariableTable:  
       Start  Length  Slot  Name   Signature  
       10      0      3    k       I  
       0      13      0    this       LFoo;  
       2      11      1    i       I  
       4      9      2    j       I  
       12      1      3    l       I  
      
      StackMapTable: number_of_entries = 1  
       frame_type = 253 /* append */  
         offset_delta = 10  
         locals = [ int, int ]  
    

    隐式的第一个基本块的stack frame map是从方法签名计算出来的。这个例子foo是个实例方法,没有显示声明的参数,所以参数个数是1,也就是隐藏参数this。那么在字节码偏移量0的位置上,操作数栈为空,
    局部变量区:[ Foo ]

    下一个基本块从字节码偏移量10开始。此处变量k已经过了作用域,所以局部变量区的有效内容应该是:
    局部变量区:[ Foo, int, int ]
    这就比前一个基本块开头处的状态多了2个局部变量,类型分别是[ int, int ],所以就有了上面对应的StackMapTable项了,253 - 251 = 2。


    kvm 实现

    上文这是介绍了一下理论,在kvm内部是通过定义如下数据结构来实现的

    struct pointerListStruct {
        long  length;
        cellOrPointer data[1];  
    };
    

    其在分配内存的时候,其最终分配的大小为: 2 * number_of_entries.

    其最终的内存布局如下:

    在这里插入图片描述

    kvm读取StackMap属性

    kvm读取StackMap属性,是在loadCodeAttribute方法中调用loadStackMaps实现的.代码如下:

    
    unsigned short codeAttrNameIndex = loadShort(ClassFileH); // 读取name index
    unsigned int   codeAttrLength    = loadCell(ClassFileH); // 读取AttrLength
    if (!strcmp(codeAttrName, "StackMap")) {
        unsigned int stackMapAttrSize;
        if (!needStackMap) {
            raiseExceptionWithMessage(ClassFormatError,
                KVM_MSG_DUPLICATE_STACKMAP_ATTRIBUTE);
        }
        needStackMap = FALSE;
        // 真正读取
        stackMapAttrSize = loadStackMaps(ClassFileH, thisMethodH);
        if (stackMapAttrSize != codeAttrLength) {
            raiseExceptionWithMessage(ClassFormatError,
                KVM_MSG_BAD_ATTRIBUTE_SIZE);
        }
    } 
    

    loadStackMaps的代码如下:

    static long
    loadStackMaps(FILEPOINTER_HANDLE ClassFileH, METHOD_HANDLE thisMethodH)
    {
        long bytesRead;
        INSTANCE_CLASS CurrentClass = unhand(thisMethodH)->ofClass;
        START_TEMPORARY_ROOTS
    	    // 1. 读取 number_of_entries
            unsigned short nStackMaps = loadShort(ClassFileH);
            // 2. 分配内存
            DECLARE_TEMPORARY_ROOT(POINTERLIST, stackMaps,
                (POINTERLIST)callocObject(SIZEOF_POINTERLIST(2*nStackMaps),
                                          GCT_POINTERLIST));
            METHOD thisMethod = unhand(thisMethodH); /* Very volatile */
            // 为stackMap,分配内存,大小为(maxStack+frameSize + 2)* 4,这里保存verification_type_info
            unsigned tempSize = (thisMethod->u.java.maxStack + thisMethod->frameSize + 2);
            DECLARE_TEMPORARY_ROOT(unsigned short*, stackMap,
               (unsigned short *)mallocBytes(sizeof(unsigned short) * tempSize));
            unsigned short stackMapIndex;
    
            stackMaps->length = nStackMaps;
            unhand(thisMethodH)->u.java.stackMaps.verifierMap = stackMaps;
            bytesRead = 2;
    
            /*
               这里读取的数据结构如下:
             * kvm_frame {
    			u2 offset_delta;
    			u2 number_of_locals;
    			verification_type_info locals[number_of_locals];
    			u2 number_of_stack_items;
    			verification_type_info stack[number_of_stack_items];
    		   }
             *
             */
            for (stackMapIndex = 0; stackMapIndex < nStackMaps; stackMapIndex++) {
                unsigned short i, index;
                
                thisMethod = unhand(thisMethodH);
                /* Read in the offset */
                stackMaps->data[stackMapIndex + nStackMaps].cell =
                    loadShort(ClassFileH); // 读取offset_delta 在stackMaps的后面保存
                bytesRead += 2;
                
                /*
                   这里通过循环读取如下数据: 
    			   *   u2 number_of_locals;
    					verification_type_info locals[number_of_locals];
    					u2 number_of_stack_items;
    					verification_type_info stack[number_of_stack_items];
                 */
                for (index = 0, i = 0 ; i < 2; i++) {
                    unsigned short j;
                    unsigned short size = loadShort(ClassFileH); // number_of_locals,number_of_stack_items
                    unsigned short size_delta = 0;
                    unsigned short size_index = index++;
                    unsigned short maxSize = (i == 0 ? thisMethod->frameSize
                                                     : thisMethod->u.java.maxStack);
                    bytesRead += 2;
                    // 读取verification_type_info
                    for (j = 0; j < size; j++) {
                        unsigned char stackType = loadByte(ClassFileH);
                        bytesRead += 1;
    
                        /* We are reading the j-th element of the stack map.
                         * This corresponds to the value in the j + size_delta'th
                         * local register or stack location
                         *
                         * j + size_delta 对应的是local registe 或者是stack
                         */
                        if (j + size_delta >= maxSize) {
                            raiseExceptionWithMessage(ClassFormatError,
                                KVM_MSG_BAD_STACKMAP);
                        } else if (stackType == ITEM_NewObject) {
                        	/*
                        	 * Uninitialized_variable_info说明存储单元包含验证类型uninitialized(offset)。
                        	 * offset项给出了一个偏移量,表示在包含此StackMapTable属性的Code属性中,new指令创建的对象所存储的位置
                        	 * Uninitialized_variable_info {  u1 tag = ITEM_Uninitialized ;
                        	 *   u2 offset; }
                        	 */
                            unsigned short instr = loadShort(ClassFileH); // offset
                            bytesRead += 2;
                            if (instr >= thisMethod->u.java.codeLength) {
                                raiseExceptionWithMessage(ClassFormatError,
                                    KVM_MSG_BAD_NEWOBJECT);
                            }
                            stackMap[index++] = ENCODE_NEWOBJECT(instr);
                        } else if (stackType < ITEM_Object) {
                        	/*
                        	 * 数据类型
                        	 */
                            stackMap[index++] = stackType;
                            if (stackType == ITEM_Long || stackType == ITEM_Double){
                                if (j + size_delta + 1 >= maxSize) {
                                    raiseExceptionWithMessage(ClassFormatError,
                                        KVM_MSG_BAD_STACKMAP);
                                }
                                stackMap[index++] = (stackType == ITEM_Long)
                                                        ? ITEM_Long_2
                                                        : ITEM_Double_2;
                                size_delta++;
                            }
                        } else if (stackType == ITEM_Object) {
                        	/*
    						 * Object_variable_info类型说明存储单元包含某个Class的实例。由常量池在cpool_index给出的索引处的CONSTANT_CLASS_Info(§4.4.1)结构表示
    						 */
                            unsigned short classIndex = loadShort(ClassFileH);
                            CONSTANTPOOL ConstantPool = CurrentClass->constPool;
                            CLASS clazz;
                            bytesRead += 2;
                            verifyConstantPoolEntry(CurrentClass,
                                                    classIndex, CONSTANT_Class);
                            clazz = CP_ENTRY(classIndex).clazz;
                            stackMap[index++] = clazz->key;
                        } else {
                            raiseExceptionWithMessage(ClassFormatError,
                                KVM_MSG_BAD_STACKMAP);
                        }
                    }
                    stackMap[size_index] = size + size_delta; // 这里实际保存的是verification_type_info所占用的大小
                }
    
                /*
                 *  检查是否有重复
                 * */
                for (i = 0; ; i++) {
                    if (i == stackMapIndex) {
                        /* 此时没有之前的stackMap是重复的,则需要分配内存,进行数据复制 */
                        char *temp = mallocBytes(index * sizeof(unsigned short));
                        memcpy(temp, stackMap, index * sizeof(short));
                        stackMaps->data[stackMapIndex].cellp = (cell*)temp;
                        break;
                    } else {
                      unsigned short *tempMap =
                        (unsigned short *)stackMaps->data[i].cellp;
                      /*   这里获取的是Loacl的长度*/
                      unsigned short tempLen = tempMap[0];
                      /*  这里获取的是Loacl的长度 */
                      unsigned short mapLen = stackMap[0];
                      /*  tempMap[tempLen + 1] 获得是stack的长度,长度 数据数据数据数据数据数据 长度 数据数据数据数据数据数据, tempMap[0] +tempMap[tempLen + 1]
                       * 只是计算了两部分数据的长度,但是没有计算2个记录数据长度的大小.由于tempLen 的类型为unsigned short,因此+2正好可以加上2个记录数据长度的大小 */
                      tempLen += tempMap[tempLen + 1] + 2;
                      mapLen += stackMap[mapLen + 1] + 2;
                      /*  如果长度相同的话且内容相同的话,则直接引用即可.节省内存*/
                      if (mapLen == tempLen &&
                          memcmp(stackMap, tempMap,
                                 mapLen * sizeof(unsigned short)) == 0) {
                        /* We have found a duplicate */
                        stackMaps->data[stackMapIndex].cellp = (cell*)tempMap;
                        break;
                      }
                    }
                }
            }
        END_TEMPORARY_ROOTS
        return bytesRead;
    }
    

    关于该方法,注释的内容较详细,就不展开了


    参考资料

    本文的内容参考如下书籍,文章:

    1. JVM 规范, (java se 7, java se 8),涉及 StackMap的章节

    2. 能介绍一下StackMapTable属性的运作原理吗?

    展开全文
  • 本人正在使用这个,不会重启后出现故障,相当给力!
  • stack-code

    2017-10-16 22:52:56
    stack-code stack-code stack-code stack-code stack-code stack-code
  • torch.stack() 与 torch.cat()

    千次阅读 2020-01-07 15:19:04
    torch.stack()和torch.cat()都是拼接tensor常用操作,stack()可以看做并联,cat()为串联。 torch.stack() 官网:https://pytorch.org/docs/stable/torch.html#torch.stack torch.stack(tensors,dim=0,out=None)...
  • c++ stack用法详解

    千次阅读 2021-07-30 16:23:47
    stack 栈是基本的数据结构之一,特点是先进后出,就如开进死胡同的车队,先进去的只能最后出来. 在c++ 中,stack的头文件是#include<stack> stack常用操作 stack<int> q; //以int型为例 int x; q.push(x);...
  • stack用法

    千次阅读 2018-05-31 23:34:17
    一、简介 stack是一种容器适配器(STL的容器分为顺序容器和关联容器,容器适配器,是对这两类容器进行包装得到的具有更强的约束力的容器),被设计来用于操作先进后出(FILO)结构的情景,在这种情况下, 元素的...
  • CSR Harmony Wireless Software Stack V2.1.63.0.rar
  • stack工具用于分析tombstone文件

    热门讨论 2014-07-19 12:15:51
    参考 http://blog.csdn.net/koffuxu/article/details/37959071
  • android ndk-stack使用说明。

    热门讨论 2012-03-19 16:51:19
    使用cocos2d-x,jni,和android ndk,开发调试无从着手是吧,那就来使用ndk-stack吧,让你轻松自如的在eclipse下,android下调试c/c++吧。嘻嘻。好东西要分享哦。
  • np.stack()函数详解

    千次阅读 多人点赞 2020-11-18 13:40:27
    np.stack()中axis参数的深入理解 看了一下大家关于np.stack()的理解,我感觉自己还是一知半解,有点蒙。自己又想把这个函数真正的理解 ,于是花了一点时间终于对这个函数有了自己的理解,决定把自己的想法写下来与...
  • tf.stack() 详解 —》理解为主

    万次阅读 多人点赞 2019-04-18 21:07:41
    tensorflow用于矩阵拼接的方法:tf.stack() 个人参考感觉还不错的一个理解(tf.stack() 和 tf.concat()的区别):https://blog.csdn.net/Gai_Nothing/article/details/88416782 def stack(values, axis=0, name...
  • echarts设置之stack参数

    千次阅读 2019-12-20 18:06:16
    echarts设置之stack参数 1、效果 2、代码(复制可用) <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <titl...
  • 《Elastic Stack 实战手册》早鸟版首发

    千次阅读 2021-06-03 00:19:15
    以 Elasticsearch、Logstash、Kibana、Beats 等组成的 Elastic Stack,以其门槛低、上手快、版本迭代快、社区响应快等特点和优势,使得看似“遥不可及、高深莫测”的大数据存储、检索与分析技术“飞入寻常百姓家”。...
  • Stack stack = new Stack<>(); stack.push(1);//入栈 stack.push(20); 1.System.out.println(stack.peek());//查看拿到栈顶元素 不删除 结果为20 2.System.out.println(stack.pop());//出栈 删除栈顶元素 结果...
  • 文章目录Docker Stack概念命令Docker stack 实践实践环境实践过程部署一个简单服务添加监控visualizer滚动更新资源控制图形界面portainer安装前准备安装portainer Docker Stack 概念 技术由来:Docker Swarm在大...
  • np.stack 和 np.concatenate两个函数都是用来连接数组的, 但是他们之间还是有一些探讨之处,直接上代码,一看便知:   import numpy as np a = np.zeros(12).reshape(4,3,) b = np.arange(12).reshape(4,3) #...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,164,210
精华内容 465,684
关键字:

stack