Memory 按值传递与按引用传递的内存使用情况

Memory 按值传递与按引用传递的内存使用情况,memory,pass-by-reference,pass-by-value,Memory,Pass By Reference,Pass By Value,在过去的几天里,我一直在努力学习“按值传递”和“按引用传递”是否会对记忆产生不同的影响。在谷歌上搜索这个查询时,人们不断重复他们自己关于创建副本时的传递值以及原始值在传递引用中是如何受到影响的。但是我想知道是否有人可以关注内存部分。这个问题实际上很大程度上取决于特定的语言,因为有些语言允许您明确定义何时要通过值传递变量,何时通过引用传递变量,有些语言对不同类型的变量总是以相同的方式传递 一种相当流行的行为类型是在简单时间内默认使用按值传递:如int、string、long、float、doubl

在过去的几天里,我一直在努力学习“按值传递”和“按引用传递”是否会对记忆产生不同的影响。在谷歌上搜索这个查询时,人们不断重复他们自己关于创建副本时的传递值以及原始值在传递引用中是如何受到影响的。但是我想知道是否有人可以关注内存部分。

这个问题实际上很大程度上取决于特定的语言,因为有些语言允许您明确定义何时要通过值传递变量,何时通过引用传递变量,有些语言对不同类型的变量总是以相同的方式传递

一种相当流行的行为类型是在简单时间内默认使用按值传递:如int、string、long、float、double、bool等

让我们展示一下记忆对理论语言的影响:

int $myVariable = 5;
此时,您已经在内存中创建了一个单变量,它采用存储整数所需的大小,比如说32位

现在要将其传递给函数:

function someFunction(int parameter)
{
    printOnScreen(parameter);
}
function printName(Person $instanceOfPerson) 
{
   printOnScreen($instanceOfPerson);
}
因此,您的代码如下所示:

function someFunction(int $parameter)
{
    printOnScreen($parameter);
}

int $myVariable = 5; //Position A
someFunction($myVariable); //Position B
...rest of the code //Position C
由于简单类型是按值传递的,因此该值会在内存中复制到另一个存储位置-因此:

在位置A期间,内存被一个int值5占用; 在位置B期间,内存被两个值为5的整数占用,因为$myVariable被复制到内存中 在位置C中,一个int值为5的内存再次被占用,因为第二个int值已被破坏,因为它仅在函数执行时才需要

这还有一些其他含义:对通过值传递的变量的修改不会影响原始变量-例如:

function someFunction(int $parameter)
{
    $parameter = $parameter + 1;
    printOnScreen($parameter);
}

int $myVariable = 5; //Position A
someFunction($myVariable); //Position B
printOnScreen($myVariable); //Position C
在位置A期间,在变量$myVariable下设置值5。 在位置B中,您通过值将其传递给一个函数,该函数在传递的值上加1。然而,由于它是一个简单的类型,通过值传递,它实际上操作一个局部变量,一个变量的副本。因此,位置C将再次只写5个原始变量,因为它没有被修改

有些语言允许您显式地传递引用,而不是使用特殊运算符传递值本身,例如&。因此,让我们再次遵循相同的示例,但有明确的信息,我们希望在函数的参数中有一个引用 -注意&:

这一次的操作和内存含义将有所不同

在位置A期间,创建一个int,每个变量总是由两个元素组成:内存中的位置和指针,即它所在的位置的标识符。为了简化这个过程,让我们假设指针总是一个字节。因此,无论何时创建变量,实际上都会创建两件事:

在内存中为本例中的值保留32位,因为它是int 指针8位[1字节] 现在在位置B期间,函数需要一个指向内存位置的指针。这意味着它将在本地仅创建指针1字节的副本,而不复制实际的保留位置,因为新指针将指向与原始指针相同的位置。这意味着在功能运行期间,您有:

指向内存中int的两个指针 为int值保留的一个位置 这两个指针都指向相同的值

这意味着对该值的任何修改都将影响这两者

因此,查看同一个示例位置C不会同时打印出6,因为在函数中,我们修改了$myVariable相同指针下的值

对于复杂类型的对象,大多数编程环境中的默认操作是传递引用指针

例如,如果您有一个类:

class Person {
   public string $name;
}
并创建其实例并设置值:

$john = new Person();
$john->name = "John Malkovic";
然后将其传递给函数:

function someFunction(int parameter)
{
    printOnScreen(parameter);
}
function printName(Person $instanceOfPerson) 
{
   printOnScreen($instanceOfPerson);
}
在内存方面,它将再次在内存1字节中创建一个指向相同值的新指针。所以有这样一个代码:

function printName(Person $instanceOfPerson) 
{
   printOnScreen($instanceOfPerson);
}

$john = new Person(); // position A
printName($john); // position B
...rest of the code // position C
在位置A中,您有:1个人,这意味着指向内存中某个位置的1个指针[1字节],该位置的大小可以存储Person类的对象

在位置B期间,您有:2个指针[2字节],但内存中仍有一个位置用于存储类person值的对象[instance]

在位置C中,位置A的情况再次出现


我希望这能为你澄清这个话题——一般来说,还有更多的内容要讲,我上面提到的只是一个一般性的解释。

传递值和传递引用是语言语义的概念;它们没有暗示任何关于实现的内容。通常,具有按引用传递的语言通过按值传递指针来实现它,然后当您读取或写入函数内的变量时,编译器将其转换为从指针的解引用读取或写入。例如,您可以想象,如果在C++中有一个函数通过引用获取参数:

struct Foo { int x; }
void bar(Foo &f) {
    f.x = 42;
}
Foo a;
bar(a);
这真的是一种语法上的糖分,比如:

struct Foo { int x; }
void bar(Foo *f_ptr) {
    (*f_ptr).x = 42;
}
Foo a;
bar(&a);
因此,通过引用进行传递的成本与p相同 按值分配指针,这确实涉及到一个副本,但它是指针的副本,只有几个字节,与指向的对象的大小无关

当您谈论通过值进行复制时,除非您知道所传递的变量或值在语言中究竟代表什么,否则这并不能真正告诉您多少。例如,Java只有传递值。但是Java中的每种类型都是基元类型或引用类型,引用类型的值都是引用,即指向对象的指针。因此,在Java中,永远不可能有一个值,一个变量持有什么值,或者一个表达式计算什么值,而这个值是一个对象;Java中的对象只能通过这些指向对象的引用指针进行操作。所以当你问用Java传递一个对象的代价时,实际上是错的,因为你不能用Java传递一个对象;您只能将引用指针传递给对象,而传递值的副本是指针的副本,只有几个字节

因此,在传递大结构时,您实际复制大结构的唯一情况是,如果您有一种语言,其中对象或结构是直接位于引用后面的值,并且您确实通过该对象/结构类型的引用进行传递。因此,例如,在C++中,可以有直接值的对象,或者可以有指向它们的指针,并且可以通过值或引用传递它们:

struct Foo { int x; }
void bar1(Foo f1) { } // pass Foo by value; this copies the entire size of Foo
void bar2(Foo *f2) { } // pass pointer by value; this copies the size of a pointer
void bar3(Foo &f3) { } // pass Foo by reference; this copies the size of a pointer
void bar4(Foo *&f4) { } // pass pointer by reference; this copies the size of a pointer

当然,每个词都有不同的语义;例如,最后一个允许函数中的代码修改传递给指向其他地方的指针变量。但是如果你担心复制的数量。只有第一个不同。在java中,只有第二个是可能的。

什么编程语言?我正在思考C++和JAVADude,我真的很感激你的答案。这个解决方案就是选择。但我有个简短的问题要问你你是什么意思,当你说每当你创建一个变量时,你会创建两个东西,一个内存空间和一个指针。那不是一个链表吗。