我的编程空间,编程开发者的网络收藏夹
学习永远不晚

怎么理解并掌握Java虚拟机内存区

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

怎么理解并掌握Java虚拟机内存区

本篇内容主要讲解“怎么理解并掌握Java虚拟机内存区”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么理解并掌握Java虚拟机内存区”吧!

一、方法区(Method Area)

方法区的概念

方法区又叫静态区,存放的是已加载的类的基本信息、常量、静态变量等。它是各个线程共享区域。

比方说我们在写 Java  代码时,每个线程度可以访问同一个类的静态变量对象。由于使用反射机制的原因,虚拟机很难推测哪那个类信息不再使用,因此这块区域的回收很难。

静态块和非静态块有什么区别?

  • 类(Class)和对象(Object)的区别与联系?

  • 为什么静态块中不能使用 this、super 关键字?

  • 为什么 java 的静态方法可以直接用类名调用?

方法区的特点

  • 线程间共享区域

方法区的异常

对这块区域主要是针对常量池回收,值得注意的是 JDK1.7 已经把常量池转移到堆里面了。同样,当方法区无法满足内存分配需求时,会抛出  OutOfMemoryError。制造方法区内存溢出,注意,必须在 JDK1.6及之前版本才会导致方法区溢出,原因后面解释,执行之前,可以把虚拟机的参数  -XXpermSize 和 -XX:MaxPermSize 限制方法区大小。

代码清单如下:

public static void printOOM() {  List<String> list = new ArrayList<String>();  int i = 0;  while (true) {  list.add(String.valueOf(i).intern());  } }

输出异常结果:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space  at java.util.Arrays.copyOf(Arrays.java:2245)  at java.util.Arrays.copyOf(Arrays.java:2219)  at java.util.ArrayList.grow(ArrayList.java:242)  at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:216)  at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:208)  at java.util.ArrayList.add(ArrayList.java:440)  at com.vprisk.knowledgeshare.MethodAreExample.main(MethodAreExample.java:15)  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)  at java.lang.reflect.Method.invoke(Method.java:606)  at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)

关于 String 的 intern() 函数intern() 的作用:

如果当前的字符串在常量池中不存在,则放入到常量池中。

上面的代码不断将字符串添加到常量池,最终肯定会导致内存不足,抛出方法区的 OOM。解释一下,为什么必须将上面的代码在 JDK1.6 之前运行。我们前面提到  JDK1.7 后,把常量池放入到堆空间中,这导致 intern() 函数的功能不同,代码清单如下:

public static void testInternMethod(){  String str1 =new StringBuilder("hua").append("chao").toString();  System.out.println(str1.intern()==str1);  String str2=new StringBuilder("ja").append("va").toString();  System.out.println(str2.intern()==str2); }

在场景 jdk6,输出结果:

false , false

在场景 jdk7,输出结果:

true , false

为什么了?

原因是在 JDK 1.6 中,intern() 方法会把首次遇到的字符串实例复制到常量池中,返回的也是常量池中的字符串的引用,而  StringBuilder 创建的字符串实例是在堆上面,所以必然不是同一个引用,返回false。在 JDK 1.7 中,intern  方法不再复制实例,常量池中只保存首次出现的实例的引用,因此intern() 返回的引用和由 StringBuilder 创建的字符串实例是同一个。为什么对  str2 比较返回的是 false呢?这是因为,JVM 中内部在加载类的时候,就已经有”java”这个字符串,不符合“首次出现”的原则,因此返回  false。

方法区的作用

方法区存放的是类信息、常量、静态变量等,是各个线程共享区域。

方法区的运用

通过过设置虚拟机的参数-XXpermSize 以及 -XX:MaxPermSize 限制方法区大小。

二、虚拟机栈(VM Stack)

虚拟机栈的概念

Java 方法执行的内存模型:

每个方法被执行的时候都会同时创建一个栈帧  (StackFrame)用于存储局部变量表、操作栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程

局部变量表

局部变量表存放了编译器克制的各种基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用(Object  reference)和字节码指令地址(returnAddress 类型)。

操作栈

操作数栈也常被称为操作栈,它是一个后入先出(Last In First Out, LIFO)栈。同局部变量表一样,操作数栈的最大深度也在编译的时候被写入到  Code 属性的max_stacks 数据项之中。操作数栈的每一个元素可以是任意的 Java 数据类型,包括 long 和 double。32  位数据类型所占的栈容量为 1,64 位数据类型所占的栈容量为 2。在方法执行的任何时候,操作数栈的深度都不会超过在 max_stacks  数据项中设定的最大值。

当一个方法刚刚开始执行的时候,这个方法的操作数栈是空的,在方法的执行过程中,会有各种字节码指令向操作数栈中写入和提取内容,也就是入栈出栈操作。例如,在做算术运算的时候是通过操作数栈来进行的,又或者在调用其他方法的时候是通过操作数栈来进行参数传递的。

举个例子,整数加法的字节码指令 iadd  在运行的时候要求操作数栈中最接近栈顶的两个元素已经存入了两个int型的数值,当执行这个指令时,会将这两个int值和并相加,然后将相加的结果入栈。

操作数栈中元素的数据类型必须与字节码指令的序列严格匹配,在编译程序代码的时候,编译器要严格保证这一点,在类校验阶段的数据流分析中还要再次验证这一点。再以上面的  iadd 指令为例,这个指令用于整型数加法,它在执行时,最接近栈顶的两个元素的数据类型必须为int 型,不能出现一个 long 和一个float 使用 iadd  命令相加的情况。

动态链接

每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态连接。我们知道 Class  文件的常量池有存有大量的符号引用,字节码中的方法调用指令就以常量池中指向方法的符号引用为参数。这些符号引用一部分会在类加载阶段或第一次使用的时候转化为直接引用,这种转化称为静态解析。另外一部分将在每一次的运行期间转化为直接引用,这部分称为动态连接。

虚拟机栈的特点

  • 线程私有

  • 生命周期与线程相同

虚拟机栈的异常

一种是 StackOverflowError

当前线程如果请求的栈深度大于虚拟机所允许的深度时,则会抛出该异常。例如,将一个函数反复递归自己,最终会出现栈溢出错误(StackOverflowError)。

代码清单如下:

public class StackOverflowErrorDemo {  public static void main(String []args){  printStackOverflowError();  }  public static void printStackOverflowError(){  printStackOverflowError();  } }

输出异常结果:

Exception in thread "main" java.lang.StackOverflowError stack length:9482  at com.itech.jvm.demo.StackOverflowErrorDemo.printStackOverflowError(StackOverflowErrorDemo.java:22)  at com.itech.jvm.demo.StackOverflowErrorDemo.printStackOverflowError(StackOverflowErrorDemo.java:22)  at com.itech.jvm.demo.StackOverflowErrorDemo.printStackOverflowError(StackOverflowErrorDemo.java:22)  at com.itech.jvm.demo.StackOverflowErrorDemo.printStackOverflowError(StackOverflowErrorDemo.java:22)  at com.itech.jvm.demo.StackOverflowErrorDemo.printStackOverflowError(StackOverflowErrorDemo.java:22)  at com.itech.jvm.demo.StackOverflowErrorDemo.printStackOverflowError(StackOverflowErrorDemo.java:22)  at com.itech.jvm.demo.StackOverflowErrorDemo.printStackOverflowError(StackOverflowErrorDemo.java:22)  at com.itech.jvm.demo.StackOverflowErrorDemo.printStackOverflowError(StackOverflowErrorDemo.java:22)  at com.itech.jvm.demo.StackOverflowErrorDemo.printStackOverflowError(StackOverflowErrorDemo.java:22)

需要说明的是,在单个线程环境下,无论是栈帧太大,还是虚拟机栈容量太小,当内存无法分配时,虚拟机都会抛出 StackOverflowError  异常。

一种是 OOM 异常

当虚拟机栈支持动态扩展时,如果无法申请到足够多的内存时就会抛出 OOM 异常。

代码清单如下:

public class VMOOMDemo {  public static void main(String[] args) throws Throwable {  VMOOMDemo demo = new VMOOMDemo();  demo.printVMOOM();  }  public void printVMOOM() {  while (true) {  new Thread() {  public void run() {  while (true) {  }  }  }.start();  }  } }

这个例子慎用...

本例通过不断地建立线程的方式产生内存溢出异常。但是,这样产生的内存溢出异常与栈空间是否足够大并不存在任何联系,或者准确地说,在这种情况下,给每个线程的栈分配的内存越大,反而越容易产生内存溢出异常。其原因是操作系统分配给每个进程的内存是有限制的,如  32 位的Windows 限制为 2 GB。。

虚拟机栈的作用

用于存储局部变量、操作栈、动态链接、方法出口

虚拟机栈的运用

对于 32 位的 jvm,默认大小为 256 kb, 而 64 位的 jvm, 默认大小为 512 kb, 可以通过 -Xss  设置虚拟机栈的最大值。不过如果设置过大,会影响到可创建的线程数量。

三、本地方法栈(Native Method Stack)

本地方法栈的概念

本地方法栈与虚拟机栈所发挥的作用很相似,他们的区别在于虚拟机栈为执行Java代码方法服务,而本地方法栈是为 Native  方法服务。与虚拟机栈一样,本地方法栈也会抛出 StackOverflowError 和 OutOfMemoryError 异常。

本地方法栈的特点

  • 线程私有

  • 为 Native 方法服务

本地方法栈的异常

与虚拟机栈一样,本地方法栈也会抛出 StackOverflowError 和 OutOfMemoryError 异常。

本地方法栈的作用

  • 与 java 环境外交互

有时 java 应用需要与 java 外面的环境交互。这是本地方法存在的主要原因,你可以想想 java  需要与一些底层系统如操作系统或某些硬件交换信息时的情况。

本地方法正是这样一种交流机制:它为我们提供了一个非常简洁的接口,而且我们无需去了解 java 应用之外的繁琐的细节。

  • 与操作系统交互

JVM 支持着 java 语言本身和运行时库,它是 java  程序赖以生存的平台,它由一个解释器(解释字节码)和一些连接到本地代码的库组成。然而不管怎样,它毕竟不是一个完整的系统,它经常依赖于一些底层(underneath  在下面的)系统的支持。这些底层系统常常是强大的操作系统。通过使用本地方法,我们得以用 java 实现了 jre 的与底层系统的交互,甚至 JVM  的一些部分就是用 C 写的,还有,如果我们要使用一些 java 语言本身没有提供封装的操作系统的特性时,我们也需要使用本地方法。

Sun's Java Sun 的解释器是用 C 实现的,这使得它能像一些普通的 C 一样与外部交互。jre 大部分是用java  实现的,它也通过一些本地方法与外界交互。例如:类 java.lang.Thread

的 setPriority() 方法是用 java 实现的,但是它实现调用的是该类里的本地方法setPriority0()。这个本地方法是用 C  实现的,并被植入 JVM 内部,在 Windows 95 的平台上,这个本地方法最终将调用 Win32 SetPriority()  API。这是一个本地方法的具体实现由JVM直接提供,更多的情况是本地方法由外部的动态链接库(external dynamic link  library)提供,然后被 JVM 调用。

四、Java 堆(Heap)

Java 堆的概念

Java  堆可以说是虚拟机中最大一块内存了。它是所有线程所共享的内存区域,几乎所有的实例对象都是在这块区域中存放。当然,随着JIT编译器的发展,所有对象在堆上分配渐渐变得不那么“绝对”了。

Java 堆是垃圾收集器管理的主要区域。由于现在的收集器基本上采用的都是分代收集算法,所有 Java  堆可以细分为:新生代和老年代。在细致分就是把新生代分为:

  • Eden 空间

  • From Survivor

  • To Survivor

根据 Java 虚拟机规范的规定:

Java  堆可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可,就像我们的磁盘空间一样。在实现时,既可以实现成固定大小的,也可以是可扩展的,不过当前主流的虚拟机都是按照可扩展来实现的。

Java 堆的特点

  • 线程间共享区域,在虚拟机启动时创建

  • 是虚拟机中最大的一块内存,几乎所有的实例对象都是在这块区域中存放

Java 堆的异常

当堆无法再扩展时,会抛出 OutOfMemoryError 异常。

Java 堆的作用

唯一目的就是存放对象实例,几乎所有的对象实例都在 java 堆中分配内存

Java 堆的运用

通过 -Xmx 和 -Xms 控制

五、程序计算器(Program Counter Register)

程序计算器的概念

类似于 PC 寄存器,程序计数器是线程私有的区域,每个线程都有自己的程序计算器。可以把它看成是当前线程所执行的字节码的行号指示器。

程序计算器的特点

  • 线程私有

  • 占用的内存空间小

  • 此内存区域是唯一一个在Java虚拟机规范中没有规定任何OOM(OutOfMemoryError)情况的区域

程序计算器的异常

此内存区域是唯一一个在 Java 虚拟机规范中没有规定任何 OOM(OutOfMemoryError)情况的区域

程序计算器的作用

  • 信号指示器:多线程间切换时,需恢复每一个线程的当前执行位置,通过程序计数器中的值寻找要执行的指令的字节码

  • 如果线程在执行 Java 方法,计数器记录的是正在执行的虚拟机字节码指令地址;如果执行的是 Native  方法,计数器的值为空(Undefined)。

程序计算器的运用

通过 -Xmx 和 -Xms 控制

六、直接内存(Direct Memory)

什么是直接内存与非直接内存?

根据官方文档的描述:

A byte buffer is either direct or non-direct. Given a direct byte buffer, the  Java virtual machine will make a best effort to perform native I/O operations  directly upon it. That is, it will attempt to avoid copying the buffer's content  to (or from) an intermediate buffer before (or after) each invocation of one of  the underlying operating system's native I/O operations.

byte byffer 可以是两种类型,一种是基于直接内存(也就是非堆内存);另一种是非直接内存(也就是堆内存)。

直接内存(Direct Memory)既不属于虚拟机运行时数据区的一部分,也不属于  Java虚拟机规范中定义的内存区域,但是这部分内存却被频繁地使用,而且还可能导致OutOfMemoryError 异常出现。

对于直接内存来说,JVM 将会在 IO 操作上具有更高的性能,因为它直接作用于本地系统的 IO 操作。而堆内存如果要作 IO  操作,会先复制到直接内存,再利用本地 IO 处理。

从数据流的角度,非直接内存的作用链:

本地IO-->直接内存-->非直接内存-->直接内存-->本地IO

而直接内存的作用链:

本地IO-->直接内存-->本地IO

很明显,在做 IO 处理时,比如网络发送大量数据时,直接内存会具有更高的效率。

A direct byte buffer may be created by invoking the allocateDirect factory  method of this class. The buffers returned by this method typically have  somewhat higher allocation and deallocation costs than non-direct buffers. The  contents of direct buffers may reside outside of the normal garbage-collected  heap, and so their impact upon the memory footprint(内存占用) of an application  might not be obvious. It is therefore recommended that direct buffers be  allocated primarily for large, long-lived buffers that are subject to the  underlying system's native I/O operations. In general it is best to allocate  direct buffers only when they yield a measureable gain in program  performance.

但是由于直接内存使用allocateDirect  创建,它比申请普通的堆内存需要耗费更高的性能。不过它不会占用应用的堆内存。所以,当你有大量数据要缓存时,并且它的生命周期又比较长,那么使用直接内存是个不错的选择。但如果该选择不能带来显著的性能提升,推荐使用堆内存。

在 JDK1.4 的 NIO 中,ByteBuffer 有个方法是:

public static ByteBuffer allocateDirect(int capacity) {  return new DirectByteBuffer(capacity); } DirectByteBuffer(int cap) {  ......  protected static final Unsafe unsafe = Bits.unsafe();  unsafe.allocateMemory(size);  ...... } public final class Unsafe {  ......  public native long allocateMemory(long var1);  ...... }

另外直接内受限于本机总内存(包括 RAM 及 SWAP 区或者分页文件)的大小及处理器寻址空间的限制。

服务器管理员配置虚拟机参数时,一般会根据实际内存设置 -Xmx  等参数信息,但经常会忽略掉直接内存,使得各个内存区域的总和大于物理内存限制(包括物理上的和操作系统级的限制),从而导致动态扩展时出现  OutOfMemoryError 异常。

直接内存的特点

  • 不受 Java 堆大小的限制

  • 既不是虚拟机运行时数据区的一部分,也不是 Java 虚拟机规范中定义的内存区域,不会占用应用的内存

  • IO 操作上具有更高的性能,因为它直接作用于本地系统的 IO 操作

  • 它比申请普通的堆内存需要耗费更高的性能。

直接内存的异常

动态扩展时出现 OutOfMemoryError 异常

直接内存的作用

基于通道(Channel)与缓冲区(Buffer)的 I/O 方式,它可以使用 Native 函数库直接分配堆外内存,然后通过一个存储在 Java  堆里面的 DirectByteBuffer 对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在 Java 堆和Native  堆中来回复制数据。

直接内存的运用

XX:MaxDirectMemorySize=10M

直接内存的使用场景

例如在 IO 处理时,比如网络发送大量数据时,直接内存会具有更高的效率。

到此,相信大家对“怎么理解并掌握Java虚拟机内存区”有了更深的了解,不妨来实际操作一番吧!这里是编程网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

怎么理解并掌握Java虚拟机内存区

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

怎么理解并掌握Java虚拟机内存区

本篇内容主要讲解“怎么理解并掌握Java虚拟机内存区”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么理解并掌握Java虚拟机内存区”吧!一、方法区(Method Area)方法区的概念方法区又
2023-06-16

Java虚拟机内存管理该怎么理解

今天就跟大家聊聊有关Java虚拟机内存管理该怎么理解,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。Java虚拟机规范将物理内存(主内存和CPU中的缓存、寄存器)划分为程序计数器、Ja
2023-06-02

java虚拟机内存怎么设置

Java虚拟机内存区域和设置Java虚拟机(JVM)内存划分为不同的区域,包括:程序计数器、栈、堆、方法区。用户可以通过启动参数调整内存区域的大小。常用参数包括:堆大小(-Xms、-Xmx)、年轻代大小(-XX:NewSize、-XX:MaxNewSize、-XX:SurvivorRatio)、方法区大小(-XX:MetaspaceSize)。内存设置对应用程序性能有显著影响。优化准则包括:根据对象创建和丢弃率设置年轻代大小,根据对象使用设置堆大小,根据类和常量数量设置方法区大小。可以通过JMX或命令行工
java虚拟机内存怎么设置
2024-04-11

虚拟主机内存空间怎么管理

虚拟主机内存空间的管理可以通过以下几个方面来实现:1. 分配内存空间:虚拟主机可以通过内存分配算法,将可用的内存空间分配给不同的虚拟机实例。常见的分配算法有静态分配和动态分配两种。静态分配是指在启动虚拟主机时,将内存空间按比例分配给各个虚拟
2023-09-12

Java虚拟机的Heap怎么理解

本篇内容介绍了“Java虚拟机的Heap怎么理解”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!在Java虚拟机中,我是一个位高权重的大管家,
2023-06-02

虚拟主机linux内存不足怎么解决

虚拟主机的内存不足可能是由于网站访问量增加或者应用程序占用内存过多导致的。解决方法如下:1. 优化网站,减少资源占用。可以通过压缩图片、减少插件、使用缓存等方式来减少网站资源的占用。2. 升级虚拟主机的内存。如果虚拟主机的内存不足,可以考虑
2023-06-05

Java虚拟机中JVM内存结构是怎么样的

这篇文章给大家分享的是有关Java虚拟机中JVM内存结构是怎么样的的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一、JVM启动流程:JVM启动时,是由java命令/javaw命令来启动的。二、JVM基本结构:JV
2023-06-02

深入理解Java虚拟机:对象实例化及直接内存详解

在Java世界中,万物皆对象。当我们谈论一个对象时,其实质是指代一段具有特定属性和行为的内存区域。

Java虚拟机中的双亲委派机制怎么理解

Java虚拟机中的双亲委派机制怎么理解,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。Java虚拟机对class文件采用的是按需加载的方式,也就是说当需要使用该类
2023-06-22

Java是怎么运行起来的?深入理解Java虚拟机

了解JVM是如何支持Java语言和其他相关语言的,对于程序员来说是很有裨益的。本文分享一下Java的工作原理和JVM的内部结构。
Java虚拟机2024-11-30

Java中的JVM是如何实现内存管理的?(请解释Java虚拟机(JVM)如何进行内存分配与回收?)

Java虚拟机(JVM)通过自动内存管理机制,在Java程序运行时管理内存分配和回收。新创建的对象分配到堆内存的年轻代,称为伊甸园,存活时间增长后晋升到幸存者区域,再晋升到年老代。JVM使用不同的垃圾回收器,如标记-清除、复制和标记-整理,清除垃圾对象。此外,JVM还提供其他内存管理机制,如本地内存、栈内存和方法区,确保程序稳定运行。
Java中的JVM是如何实现内存管理的?(请解释Java虚拟机(JVM)如何进行内存分配与回收?)
2024-04-02

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录