热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

c++和Java数组内存空间申请

c中由于数组导致的内存溢出处理之前实现图论算法的时候碰到过超大的整型数组,用c去实现着实会碰到一些莫名其妙的内存溢出问题。例如:我们想定义一个200

c++中由于数组导致的内存溢出处理

之前实现图论算法的时候碰到过超大的整型数组,用c++去实现着实会碰到一些莫名其妙的内存溢出问题。

例如:我们想定义一个 2000*2000 的 2d 数组,甚至是这样大小的 2d 的 vector,如果是直接定义成局部变量,那么将会直接报内存溢出错(大家可以计算一下这样大小的数组会占据多少内存空间)。

那么为什么定义成局部变量会导致内存溢出呢?笔者认为是因为程序中函数的调用或者说是运行其实是在栈中执行的,而栈的空间是很有限的,所以说定义过大的局部变量必然导致栈溢出(Stack overflow)错误。

因此对于较大的局部变量我们需要将其定义为全局的,尤其在函数的递归调用中。亲测 2d vector 当大小超过100,就已经能够导致溢出错了(vector 中的自增长方法会开辟更大的空间)。

众所周知,数组是一种顺序存储的数据结构,在定义数组时,首先要确定数组的大小。前面提到的静态数组在编译时就需要确定数组的大小,所以,为了防止内存溢出,我们尽量将数组定义的大一些,但是这样太过浪费内存。甚至当超过一定大小之后,编译会报错,例如直接定义一个全局的:

int a[3000][3000];

这样程序可能连编译都无法通过。

这样大型的数组需要通过定义动态数组。动态数组不需要在编译时就确定大小,它的大小在程序运行过程中确定,所以可以根据程序需要而灵活的分配数组的大小,相比静态数组,它更“灵活”、“自由”。但是动态数组需要进行显式的内存释放。

int **Ctable; // 全局的二次指针
void DynamicCreate2Array()
{// 二维动态数组的空间开辟 3000*3000大小int m &#61; 3000, n &#61; 3000;int i;cout << "############## call the CTable create func #############" << endl;//动态开辟空间 Ctable &#61; new int*[m]; //开辟行 for (int i &#61; 0; i < m; i&#43;&#43;)Ctable[i] &#61; new int[n]; //开辟列 int val &#61; 0;for (i &#61; 0; i < m; i&#43;&#43;)for (int j &#61; 0; j < n; j&#43;&#43;){Ctable[i][j] &#61; 0;val &#43;&#43;; } cout << "items: " << val << endl;
}
int main(){DynamicCreate2Array(); // 为CTable动态开辟内存int count &#61; 3000;//初始化Ctable全为0for(int i &#61; 0; i < count; i&#43;&#43;)for(int j &#61; 0; j < count; j&#43;&#43;)Ctable[i][j] &#61; 0;// 输出Ctablefor(int i &#61; 0; i < count; i&#43;&#43;)for(int j &#61; 0; j < count; j&#43;&#43;)printf("%d\t", Ctable[i][j]);//释放Ctable开辟的资源 for (int i &#61; 0; i < 3000; i&#43;&#43;)delete[] Ctable[i];delete[] Ctable;}

Java 中对大数组的处理

Java 程序在运行时都要开辟空间&#xff0c;任何软件在运行时都要在内存中开辟空间&#xff0c;Java虚拟机运行时也是要开辟空间的。JVM运行时在内存中开辟一片内存区域&#xff0c;启动时在自己的内存区域中进行更细致的划分&#xff0c;因为虚拟机中每一片内存处理的方式都不同&#xff0c;所以要单独进行管理。

JVM内存的划分有五片&#xff1a;


  1. 寄存器

  2. 本地方法区

  3. 方法区

  4. 栈内存

  5. 堆内存

我们重点来说一下堆和栈&#xff1a;


栈内存

栈内存首先是一片内存区域&#xff0c;存储的都是局部变量&#xff0c;凡是定义在方法中的都是局部变量&#xff08;方法外的是全局变量&#xff09;&#xff0c;for循环内部定义的也是局部变量&#xff0c;是先加载函数才能进行局部变量的定义&#xff0c;所以方法先进栈&#xff0c;然后再定义变量&#xff0c;变量有自己的作用域&#xff0c;一旦离开作用域&#xff0c;变量就会被释放。栈内存的更新速度很快&#xff0c;因为局部变量的生命周期都很短。


堆内存

存储的是数组和对象&#xff08;其实数组就是对象&#xff09;&#xff0c;凡是new建立的都是在堆中&#xff0c;堆中存放的都是实体&#xff08;对象&#xff09;&#xff0c;实体用于封装数据&#xff0c;而且是封装多个&#xff08;实体的多个属性&#xff09;&#xff0c;如果一个数据消失&#xff0c;这个实体也没有消失&#xff0c;还可以用&#xff0c;所以堆是不会随时释放的&#xff0c;但是栈不一样&#xff0c;栈里存放的都是单个变量&#xff0c;变量被释放了&#xff0c;那就没有了。堆里的实体虽然不会被释放&#xff0c;但是会被当成垃圾&#xff0c;Java有垃圾回收机制不定时的收取。

下面我们通过一个图例详细讲一下堆和栈&#xff1a;

比如主函数里的语句

int [] arr &#61; new int [3];

在内存中是怎么被定义的&#xff1a;

主函数先进栈&#xff0c;在栈中定义一个变量arr,接下来为arr赋值&#xff0c;但是右边不是一个具体值&#xff0c;是一个实体。实体创建在堆里&#xff0c;在堆里首先通过new关键字开辟一个空间&#xff0c;内存在存储数据的时候都是通过地址来体现的&#xff0c;地址是一块连续的二进制&#xff0c;然后给这个实体分配一个内存地址。数组都是有一个索引&#xff0c;数组这个实体在堆内存中产生之后每一个空间都会进行默认的初始化&#xff08;这是堆内存的特点&#xff0c;未初始化的数据是不能用的&#xff0c;但在堆里是可以用的&#xff0c;因为初始化过了&#xff0c;但是在栈里没有&#xff09;&#xff0c;不同的类型初始化的值不一样。所以堆和栈里就创建了变量和实体&#xff1a;
在这里插入图片描述
那么堆和栈是怎么联系起来的呢?

我们刚刚说过给堆分配了一个地址&#xff0c;把堆的地址赋给arr&#xff0c;arr就通过地址指向了数组。所以arr想操纵数组时&#xff0c;就通过地址&#xff0c;而不是直接把实体都赋给它。这种我们不再叫他基本数据类型&#xff0c;而叫引用数据类型。称为arr引用了堆内存当中的实体。&#xff08;可以理解为c或c&#43;&#43;的指针&#xff0c;Java成长自c&#43;&#43;和c&#43;&#43;很像&#xff0c;优化了c&#43;&#43;&#xff09;

如果当int [] arr&#61;null;

arr不做任何指向&#xff0c;null的作用就是取消引用数据类型的指向。

当一个实体&#xff0c;没有引用数据类型指向的时候&#xff0c;它在堆内存中不会被释放&#xff0c;而被当做一个垃圾&#xff0c;在不定时的时间内自动回收&#xff0c;因为Java有一个自动回收机制&#xff0c;&#xff08;而c&#43;&#43;没有&#xff0c;需要程序员手动回收&#xff0c;如果不回收就越堆越多&#xff0c;直到撑满内存溢出&#xff0c;所以Java在内存管理上优于c&#43;&#43;&#xff09;。自动回收机制&#xff08;程序&#xff09;自动监测堆里是否有垃圾&#xff0c;如果有&#xff0c;就会自动的做垃圾回收的动作&#xff0c;但是什么时候收不一定。

所以堆与栈的区别很明显&#xff1a;

1.栈内存存储的是局部变量而堆内存存储的是实体&#xff1b;

2.栈内存的更新速度要快于堆内存&#xff0c;因为局部变量的生命周期很短&#xff1b;

3.栈内存存放的变量生命周期一旦结束就会被释放&#xff0c;而堆内存存放的实体会被垃圾回收机制不定时的回收。

import java.util.Scanner;public class MyArray {public static void main(String[] args) {// 动态数组int col, row;Scanner sc &#61; new Scanner(System.in);String line &#61; sc.nextLine();String [] nums &#61; line.split(" ");col &#61; Integer.parseInt(nums[0]);row &#61; Integer.parseInt(nums[1]);System.out.println(col &#43; row);int [][] bigArray &#61; new int[col][row];for (int i &#61; 0; i < col; i&#43;&#43;) {for (int j &#61; 0; j < row; j&#43;&#43;) {bigArray[i][j] &#61; i &#43; j;}}System.out.println(bigArray[col-1][row-1]);}
}
/* 输入与输出
3000 3000
6000
5998
*/


推荐阅读
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • 本文介绍了一个Java猜拳小游戏的代码,通过使用Scanner类获取用户输入的拳的数字,并随机生成计算机的拳,然后判断胜负。该游戏可以选择剪刀、石头、布三种拳,通过比较两者的拳来决定胜负。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文介绍了在Java中gt、gtgt、gtgtgt和lt之间的区别。通过解释符号的含义和使用例子,帮助读者理解这些符号在二进制表示和移位操作中的作用。同时,文章还提到了负数的补码表示和移位操作的限制。 ... [详细]
  • JavaSE笔试题-接口、抽象类、多态等问题解答
    本文解答了JavaSE笔试题中关于接口、抽象类、多态等问题。包括Math类的取整数方法、接口是否可继承、抽象类是否可实现接口、抽象类是否可继承具体类、抽象类中是否可以有静态main方法等问题。同时介绍了面向对象的特征,以及Java中实现多态的机制。 ... [详细]
  • 本文介绍了Java高并发程序设计中线程安全的概念与synchronized关键字的使用。通过一个计数器的例子,演示了多线程同时对变量进行累加操作时可能出现的问题。最终值会小于预期的原因是因为两个线程同时对变量进行写入时,其中一个线程的结果会覆盖另一个线程的结果。为了解决这个问题,可以使用synchronized关键字来保证线程安全。 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • 从零学Java(10)之方法详解,喷打野你真的没我6!
    本文介绍了从零学Java系列中的第10篇文章,详解了Java中的方法。同时讨论了打野过程中喷打野的影响,以及金色打野刀对经济的增加和线上队友经济的影响。指出喷打野会导致线上经济的消减和影响队伍的团结。 ... [详细]
  • 猜字母游戏
    猜字母游戏猜字母游戏——设计数据结构猜字母游戏——设计程序结构猜字母游戏——实现字母生成方法猜字母游戏——实现字母检测方法猜字母游戏——实现主方法1猜字母游戏——设计数据结构1.1 ... [详细]
author-avatar
茶香未散尽_385_312
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有